How to use add elements to a matrix? - netlogo

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.

Related

How to find the largest network cluster?

"nw:weak-component-clusters" in the Networks extension will return a list of weakly connected agentsets. I would like to output the number of turtles in the biggest of these.
So
show nw:weak-component-clusters
observer: [(agentset, 15 turtles) (agentset, 20 turtles) (agentset, 16 turtles)]
would return 20.
Is there an easy way to do this please?
This isn't pretty but it will work:
to find_max
let my_list []
let my_max 0
let turt_list nw:weak-component-clusters
foreach turt_list [x -> ask x [set my_list lput count x my_list]]
set my_max max my_list
show my_max
end
There is a simpler approach using map:
to-report count-of-largest-cluster
report max (map count nw:weak-component-clusters)
end
map takes a reporter and a list as inputs, and reports a list whose items are the result of the input reporter being run for every item of the input list.
nw:weak-component-clusters is a list of agentsets, therefore map count nw:weak-component-clusters is a list of each agentset's count. Note that the parentheses in my solution are optional and only there for readability.

Accessing owned traits in netlogo with nested ask

This is what i want to do:
patches-own[
trait1
trait2
trait3
]
let similarityCounter 0
ask one-of patches[
ask one-of neighbors[
**for-each trait[
if neighborTrait = patchTrait**[
set similarityCounter (similarityCounter + 1)
]
]
]
]
The part between ** is what I'm unsure about. How does one iterate over the patch-own parameters and compare between patch and neighbor?
How about you create a list for each patch of their trait values and count matches in the two lists? It would looks something like this.
to testme
let similarityCounter 0
ask one-of patches
[ let mytraits (list trait1 trait2 trait3)
let theirtraits [(list trait1 trait2 trait3)] of one-of neighbors
set similarityCounter length filter [ xx -> xx ] (map = mytraits theirtraits)
]
end
The final line is a little dense. What it does is compare the two lists of traits using the map function with the = operator, which will return a list of true and false values indicating whether that specific trait matches. The filter then creates a list of just the true values and the length counts the number of those true values.
Unfortunately, NetLogo doesn't do the trick of treating a true as 1 and false as 0 that you see in some languages, so you can't simply sum the match results list.
I really like Jen's answer, but just for fun, I'd like to provide an alternative way to approach the problem that uses Jen's idea of treating true as 1 and false as 0.
But first, I think that, depending on the rest of your model, it could have been a good idea for you to store your traits directly in a list instead of separate variables. In programming, having variable names with a numeric suffix like trait1, trait2, etc. is usually a hint that a list should be used instead.
Nevertheless, we will leave your general design alone for now and just provide a small function that makes it easy to package your traits into a list:
to-report traits ; patch reporter
report (list trait1 trait2 trait3)
end
Once you have that, you can write something like [ traits ] of one-of patches to get a list of the patche's traits.
Now let's attack the problem of turning true and false into ones and zeros in a similar way. It's true that NetLogo doesn't provide that conversation automatically (which I think is a good thing) but it's easy to write our own function for that:
to-report bool-to-int [ yes? ]
report ifelse-value yes? [ 1 ] [ 0 ]
end
We are now ready to write our main function. We will use Jen's approach of mapping over the = operator to convert our lists of traits to a list of boolean (i.e., true/false) values, and we will then use map again to convert that list into a list of 1 and 0. Once we have that, all that is left is to sum it! Here we go:
to-report similarity-with [ other-patch ] ; patch reporter
report sum map bool-to-int (map = traits [ traits ] of other-patch)
end
Having that reporter makes it really easy to get the similarity between two patches. You can now say things like:
print [ similarity-with one-of neighbors ] of one-of patches
Notice how I have approached the problem by building small pieces that be combined together. I really like this way of proceeding: it allows me to concentrate on one part of the problem at a time, but it's also more easy to test and results in code that I find very readable. NetLogo's to-report procedures are a great tool to achieve that kind of modularity.

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.

How to obtain a list that contains only unique values?

I have a list as follows :
[[178 440] [175 440] [160 468] [160 440]]
The values in each sub-list correspond to coordinates x, y.
I would like to obtain a list that contains only unique values of x and y.
From the list above, the results will be:
[[178 440] [160 468]]
Thanks in advance for your help.
Given your example, I assume that by "unique", you mean "not encountered so far".
Here is one way to do it, using the oh so flexible reduce:
to go
let pairs [[178 440] [175 440] [160 468] [160 440]]
print reduce [
ifelse-value (is-unique? ?2 ?1)
[ lput ?2 ?1 ]
[ ?1 ]
] fput [] pairs
end
to-report is-unique? [ pair other-pairs ]
report
(not member? (first pair) (map first other-pairs)) and
(not member? (last pair) (map last other-pairs))
end
The is-unique? reporter should be fairly easy to understand: it uses map to extract the first item (the x) of each of the other-pairs, and check that the first item of pair is not a member? of that. It performs the same check for the last item (the y).
The reduce part is a bit trickier, but not that hard either. We add an empty list at the front of your list of pairs (fput [] pairs) that we are going to use as an "accumulator" for the pairs that meet our criteria. This accumulator is going to be ?1 inside the reporter passed to reduce, and ?2 is going to be each of our pairs in turn. So what we do inside it is just check if ?2 is unique relative to the pairs accumulated so far. If it is, we add it to our list of accumulated pairs. If it's not, we leave the list as it was and just move on to the next ?2.