List multiplication in NetLogo - netlogo

I'm modeling the distribution of hoverflies in an aphid-infested crop field with flower margins. I have a couple of lists which are setup as patch variables as follows:
set nl n-values 20 [0];; number of larvae per age (in days)
set il n-values 20 [0.0001];; individual larvae growth per age (in days)
set il_growth n-values 20 [0];; growth of larvae per age (in days)
I gave the value 0.0001 instead of 0 because previously I got errors regarding the 0.
Every timestap the following happens:
to time
set nl fput item 3 peggs nl ;every day the amount of 4 days old eggs are added to the number of larvae
set il fput ((item dtl peggs) * weight_hatch) il ;the weight of the larvae that just hatched are calculated by multiplying nl by the weight they have when they hatch
set il_growth (il * e ^ (g * (aphids)*(1 - (il / weight_max))));;growth individual predator larvae in every age class
set larvae nl * il_growth; the total biomass of al larvae in a patch
end
The for il_growth comes from the literature and I know that parameters/variables like e, g, aphids and weight_max aren't the problem because this formula work fine before I introduced il.
I'm not sure yet if the approach for biomass is the best way (because of the error of il that I'll describe below), but I figured that the multiplication is possible since nl and il are both lists of the same length.
When I syntax check the code it doesn't give any errors. But when I run it, it says the following: * expected input to be a number but got the list [0 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4] instead.
The * it points at is the first one in the il_growth formula.
I thought that this could be caused because the code needs il to be a number and not a list. Then I found on google that this could be fixed by the functions 'foreach' or 'map'.
With foreach I tried this:
set il_growth foreach il (il * e ^ (g * (aphids)*(1 - (il / weight_max))))
This gave the error 'set expected 2 inputs'. I also tried many other configurations with foreach, but none worked.
With map I tried this:
set il_growth map report_il il
to-report report_il
report (il * e ^ (g * (aphids)*(1 - (il / weight_max))))
end
This gave me the same error as before: * expected input to be a number but got the list [0 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4 1.0E-4] instead.

We don't need to know everything you have tried if the attempt didn't help, just enough to understand the code that you are trying to fix and a description of the problem. You definitely can't simply multiply lists the way you have, even if they are the same length. This is a complete model that will generate the same error message:
to testme1
let list1 [1 2 3]
let list2 [4 5 6]
print list1 * list2
end
If what you are trying to do is multiply the two lists on an item by item basis, then you need map. Here is the equivalent model:
to testme2
let list1 [1 2 3]
let list2 [4 5 6]
print (map * list1 list2)
end
So, if I have understood your question, replace set larvae nl * il with set larvae (map nl * il). If that doesn't fix your problem, please edit your question to more clearly identify what you are trying to resolve.
UPDATE: for comment
Okay, from your comment, the line set il_growth (il * e ^ (g * (aphids)*(1 - (il / weight_max)))) is throwing the error. Just like the map is necessary for multiplying lists, it is necessary for more complicated arithmetic. You are multiplying the list il by something with a bunch of values (e, g, aphids, weight_max) and operators and the list il again.
Try replacing with this (untested):
set il_growth map [ thisval -> thisval * e ^ (g * (aphids)*(1 - (thisval / weight_max)))) ] il
What this (sort of) does is run through the list il, giving the current item to the temporary variable named 'thisval', and does the calculations on the individual value rather than the list. But it applies to the whole list.

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.

Netlogo: How to compute sum of items of lists within a list?

I would like to make the sum = the total of pollen recieved by a plant from other plants (Donnors) which is stored in a list of a list (own by each turtle = plant).
The following code make an error (when computing the sum):
OF expected input to be an agent or agentset but got the list
[[119.05593 50 50] [301.25853 50 50] [30.23906 50 50] [460.525845 50
50] [55.16717 50 50] [301.25853 50 50]] instead.
Does any one could help me about the mistake in the line "set Tot_pol sum ..." ?
Many thanks for your help.
to check-pol [m] ;; we check the pollen recieved by the two morphs
set Donnors [] ;; empty list of pollen donnors
ask zsps with [morph = m] ;; morph of the pollen reciever
[
set totpol 0
;; check for pollen donnors and morph for compatiblity within a radius :
ask zsps with[distance myself <= 20 and morph != m]
[
set totpol (NMaleFlowers * 100 * item round (distance myself) pollination-list) ;; the farther the less pollen
set Donnors lput [ (list totpol NMaleFlowers NFemFlowers)] of myself Donnors
]
set Tot_pol sum [ item (position 0 Donnors) Donnors ] of Donnors ;; total of pollen recieved
]
end
Luke's answer is good and should fix your problem. I suspect, however, that you are going to be doing lots of these types of sums. You may wish to set up a to-report that you can use for whichever item you want to sum over, just by passing the item number and the name of the list of lists. It would look like this:
to-report sum-item [#pos #listoflists ]
let items map [ x -> item #pos x ] #listoflists
report reduce [ [a b] -> a + b] items
end
The first line extracts the relevant item (remember index from 0) into a new list which the second line sums.
You would then use it with set Tot_pol sum-item 0 Donnors
Here's an answer that is not actually responding to your question. Instead, it is a more NetLogo-ish way of doing what I think you are trying to do with your code.
to check-pol [m]
ask zsps with [morph = m]
[ let senders zsps with [distance myself <= 20 and morph != m]
set totpol sum [NMaleFlowers * 100 * round (distance myself)] of senders
]
end
Your code gets into levels of ask that I think are unnecessary. What I think you are doing with your list is keeping track of the pollen donors. But an agentset is a cleaner approach and then you can simply pull out the information you want from the agentset using of.
Further, when you ask zsps with[distance myself <= 20 and morph != m] to set variable values in your code, then THOSE agents (not the receiving agent) are the ones having their variables changed. I think you are trying to take the perspective of the receiver of pollen, who looks around and received pollen from the other agents that are close enough. So the receiving agent should have the value changed.
This is not tested.
I'm not 100% sure what you're after here (you may want to look at the Minimum, Complete, and Verifiable Example guidelines), but if I'm reading you right you want the sum of the first item for each entry in the Donners list.
As to why your approach didn't work- NetLogo is telling you with that error that you've used of with a list, but of only works with agents or agentsets. Instead, you have to use a list processing approach. The simplest way might be to use sum in conjunction with map first in order to get what you need:
to sum-first-item
let example-list [ [ 1 2 3 ] [ 4 5 6 ] [ 7 8 9 ] ]
let sum-of-firsts sum map first example-list
print sum-of-firsts
end
To translate to Donnors, try:
set Tot_pol sum map first Donnors
That should work, but without reproducible a code example I can't check.

Decimal places in a monitor

I have set decimal places in a Netlogo Monitor to 4. Numbers that end in 0's get truncated (3.4500 appears as 3.45, 3.4550 appears as 3.455). Is there some way to retain the 4 decimal appearance?
Suppose we define:
to-report zero-pad [n places]
let result (word precision n places)
if not is-number? position "." result [
set result (word result ".")
]
let padding-amount position "." result - length result + places + 1
let padding reduce word fput "" n-values padding-amount [0]
report (word result padding)
end
Let's see if it works:
observer> show zero-pad 1.2 3
observer: "1.200"
observer> show zero-pad 1.2468 2
observer: "1.25"
Looks good. So now, in the monitor, instead of just x, write e.g. zero-pad x 4 if you want four decimal places.

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

NetLogo: procedure for performing an operation on one item in a list in a compact way?

New to NetLogo... wondering if there's a procedure that performs an operation on one item in a list in a compact way (like map but for one item).
For example, say I wanted to add 3 to the item at index i in list blah.
Right now I'm doing this like:
set blah replace-item i blah (item i blah + 3)
It seems a little clunky, and like there would be a procedure that does that, but I haven't been able to find one. Just wanted to make sure I wasn't missing something.
Thank you!
Taylor
There isn't something built in that does this. But you could define it yourself as a procedure that takes a task as input:
;; replace item i of xs with the result of applying fn to that item
to-report mapping-replace-item [i xs fn]
report replace-item i xs (runresult fn item i xs)
end
Sample usage:
observer> show mapping-replace-item 2 [10 20 30 40] task [? * ?]
observer: [10 20 900 40]