Nested foreach in NetLogo - netlogo

I am trying to calculate the Gini coefficient of a set of numbers. The Gini coefficient is half the mean absolute difference. That is, for every possible pair of numbers in the list, I need to take their absolute difference and add these differences together (and some other stuff). This is my code
to-report calc-Gini [list-Values]
let sumdiff 0
foreach list-Values
[ foreach list-Values
[ set sumdiff sumdiff + abs ( ?1 - ?2 )
]
]
report 0.5 * sumdiff / (mean list-Values * (length list-Values) ^ 2)
end
When I test it (eg show calc-Gini (list 1 2 3)) I get an error "task expected 2 inputs, but only got 1" on the second foreach.
I think the problem is that NetLogo wants to run through the foreach loops simultaneously. So if the list length is N, then it creates only N pairs (that is, first item in list1 and first item in list2, then the second item in each list etc) which is where the requirement for equal length lists comes from. But I need it to work with the N^2 pairs obtained by crossing the lists.
How can I make the nested foreach do what I want and/or is some other primitive more appropriate?

NetLogo doesn't have a mechanism for binding ?1 and ?2 to an outer and an inner task. When it sees ?1 and ?2 in your code, it expects that both inputs will come from the inner task. And since the inner foreach only provides one input, NetLogo complains.
You can get around that problem by simply assigning the input of the outer foreach to a local variable:
to-report calc-Gini [list-Values]
let sumdiff 0
foreach list-Values
[ let v ?
foreach list-Values
[ set sumdiff sumdiff + abs ( v - ? )
]
]
report 0.5 * sumdiff / (mean list-Values * (length list-Values) ^ 2)
end
That being said, here is an alternative implementation:
to-report calc-gini [ xs ]
report 0.5 * sum map [ sum-diff ? xs ] xs / (mean xs * (length xs) ^ 2)
end
to-report sum-diff [ x xs ]
report sum map [ abs (x - ?) ] xs
end

I can't solve your nested foreach approach, but this might be an alternative way to do your calculation:
If you use ordered data, you can use this equation for the Gini coefficient (given a vector $y$ with $y_i$, $i=1,...,n$)
$$ G(y) = \frac{1}{n} (n + 1 - 2 * \frac{ \sum_{i=1}^{n} (n + 1 - i) y_{i} }{ \sum_{i=1}^{n} y_i} $$
and the following reporter should deliver the result in NetLogo:
to-report calc-Gini [list-Values]
let values sort list-Values ; making sure values are in a non-decreasing order
let n length values
let i 1
let numerator []
foreach values
[ set numerator lput ( (n + 1 - i) * ? ) numerator
set i i + 1
]
report 1 / n * ( n + 1 - 2 * (sum(numerator) / sum(values)) )
end

Related

Cannot find item in list based on index in NetLogo

im using a sorted list in netlogos but when i run my code i get an error message that it can't find element 3 because the lenght of the list is 3, that sounds really strange and counter intuative to me. what goes wrong
globals [
allehøjder
min_højde
nedre_højde
median_højde
øvre_højde
max_højde
]
breed [personer en_person]
personer-own [højde skostørrelse]
to setup ; runs when the button "setup" is pressed
clear-all
;kom alle højder ind i højde
;sorter højde listen
;find 5 kvartil værdien ud fra højder[]
create-personer 3
[
set color white
set højde (150 + ( random ( 190 - 150 )))
set skostørrelse (38 + (random ( 47 - 38 )) )
setxy random-xcor random-ycor
set size 10
]
set allehøjder [højde] of personer
set alleskostørrelser [skostørrelse] of personer
show sort allehøjder
show sort alleskostørrelser
;sætter de 5 kvartilværdier for højde
; sætter min
set min_højde item 1 (sort allehøjder)
;sætter max
**bold** set max_højde item 3 (sort allehøjder)
; sætter median
ifelse 3 mod 2 = 0
;lige antal
[
set median_højde item ((3 + 1 / 2) ) (sort allehøjder)
]
;ulige antal
[
set median_højde ((item ((3 + 1) / 2) (sort allehøjder) + item (((3 + 1) / 2) + 1) (sort allehøjder)) / 2)
]
reset-ticks
end
regards morten
The indexing of lists' items starts from 0, hence the third element will have index 2.
The NetLogo Programming Guide and the NetLogo Dictionary linked above should have you covered with this type of problems.

NetLogo database resultlist loading problem

I am trying to get some integer values from database (almost 30.000 rows) and it gives error "error while observer running READ-FROM-STRING in procedure GET-IMAGEDB Expected a constant." I considered it may happen because of requiring waiting time to not set a null value to variable of NetLogo and added "print" lines to delay the process. It worked for small sized datasets for instance 30.000 rows. However, when the dataset size increased to 250.000 rows, now I am getting same error again. I am not sure about reason of the error. I have also tried to get all rows from the dataset with single query and set it to NetLogo list, but still gives same error and extremely slow. I have attached the code. Thank you for any help.
let total ( (width + 1) * (height + 1) )
let counter 0
while [ counter < total ]
[ set query "select x, y, r, g, b, background from colorinfo where pixelId = \""
set query (word query counter "\"" )
let resultList (mysql:executeQuery db query)
let stringList item 0 resultList
print (word "wait 1")
let x read-from-string item 0 stringList
print (word "wait 2")
let y read-from-string item 1 stringList
let r read-from-string item 2 stringList
let g read-from-string item 3 stringList
let b read-from-string item 4 stringList
let background read-from-string item 5 stringList
ask patch (x + width + 2) ( y) [ set pcolor (list r g b) ]
print counter
set counter (counter + 1)
set stringList [ ]
set resultList [ ]
]

Applying a list of functions on a list of argument lists

I have a list of anonymous functions that I need to map over a list of argument lists. My desire is to obtain a list containing lists whose elements are the functions in the functions list, evaluated at each argument list.
My first thought was to map the functions list over the argument lists and then apply the functions in the functions list on each element in the arguments list.
;; definitions for k functions
let fj [ [x1 x2 ... xn ] -> <body j> ]
...
let args [ [ ... ] [ ... ] ... [ ... ] ] ;; list of arguments
let f-list ( list f1 f2 ... fk )
map [ [ arg ] -> map [ [ f ] -> ( runresult f arg ) f-list ] ] args
There is one two problem with this code:
Mapping the f-list on list arg does not behave the way I expected it to behave. Namely, running the code produces run-time errors because the functions in f-list are not defined over a list but are instead defined over a number of arguments.
In order to overcome this latter difficulty, I have redefined the functions in f-list so as to receive a list as an argument and use item in the body of the functions in order to retrieve individual parameters.
This solution, apart from the fact that, it too, feels like a hack, it is also highly impractical because it increases the code needed to obtain a given result, in a way that is highly error prone, not to mention extremely tedious ( consider having to redefine a modest number of functions with a moderate number of arguments ).
In Mathematica it is possible to transform a list of arguments to a function into a sequence ( or tuple ) of arguments by using Apply as in Apply[f, args] where args is a list of argument values.
This facilitates the application of functions on lists of argument ( lists ). Practically, one can write f ### { args1, args2, ..., argsm } and obtain a list { f[x11, x12, ..., x1n], f[x21, x22, ..., x2n], ..., f[xm1, xm2, ..., xmn] } ( where ### is just the infix notation that corresponds to Apply[f, args, 1] ).
I guess what I'm looking for is how to achieve the same result in native NetLogo code without having to resort to hacks like the one reported in the former part of this question.
some actual code
globals [ f-list args ]
to setup
let f1 [ [ arg ] -> ( ( item 0 arg ) - 5 ) ^ 2 + ( ( item 1 arg ) - 5 ) ^ 2 + 0 * ( ( item 2 arg ) - 5 ) ^ 2 ]
let f2 [ [ arg ] -> 4 * ( item 1 arg ) ^ 2 + 4 * ( item 0 arg ) ^ 2 + 0 * ( item 2 arg ) ^ 2 ]
let f3 [ [ arg ] -> 2 + ( ( item 1 arg ) - 2 ) ^ 2 + ( ( item 2 arg ) - 1 ) ^ 2 + 0 * ( item 0 arg ) ]
let f4 [ [ arg ] -> 9 * ( item 0 arg ) - ( ( item 2 arg ) - 1 ) ^ 2 + 0 * ( item 1 arg ) ]
set f-list ( list f1 f2 f3 f4 )
set args [ [ 2.04 3.09 -1.32 ] [ 5.57 -3.9 4.0 ] [ -1.1 -0.432 8.0 ] [ 1.32 -2.3 -9.103 ] ]
show map [ [ arg ] -> ( map [ [ f ] -> ( runresult f arg ) ] f-list ) ] args
end
using a setup button that calls the procedure above produces the following output:
observer: [[12.4097 54.8388 8.570500000000001 12.977599999999999] [79.53490000000001 184.9396 45.81 41.13] [66.716624 5.586496 56.914624 -58.9] [66.83239999999999 28.129599999999996 122.56060899999999 -90.190609]]
Thanks to Bryan Head, NetLogo now offers this functionality via the (experimental and undocumented) __apply and __apply-result primitives.
In your case, __apply-result is the one you need:
globals [ f-list args ]
to setup
let f1 [ [x y z] -> (x - 5) ^ 2 + (y - 5) ^ 2 + 0 * (z - 5) ^ 2 ]
let f2 [ [x y z] -> 4 * y ^ 2 + 4 * x ^ 2 + 0 * z ^ 2 ]
let f3 [ [x y z] -> 2 + (y - 2) ^ 2 + (x - 1) ^ 2 + 0 * x ]
let f4 [ [x y z] -> 9 * x - (z - 1) ^ 2 + 0 * y ]
set f-list (list f1 f2 f3 f4)
set args [[2.04 3.09 -1.32] [5.57 -3.9 4.0] [-1.1 -0.432 8.0] [1.32 -2.3 -9.103]]
print map [ arg -> map [ f -> __apply-result f arg ] f-list ] args
end
As you can see, __apply-result takes two arguments, an anonymous reporter and a list, and automatically passes the items in the list as arguments to the anonymous reporter. The __apply primitive is similar, but takes an anonymous command instead of an anonymous reporter.

NetLogo addition of nominal values giving unusual results

When a variable is being incremented by very small value (say 0.01), it is not giving proper (precise) results as expected.
Looking for suggestions(if any) to deal with the same.
globals[p]
to go
set p 0
while[p <= 1]
[
print p
set p p + 0.01
]
end
First read this:
http://floating-point-gui.de/
Then to subdivide an interval into n pieces, do this:
to-report subdivide [#xmin #xmax #n]
let ps n-values (#n + 1) [? / #n]
report map [#xmin + ? * (#xmax - #xmin)] ps
end

How make a list of cumulative sum in netlogo

How can i make a list of cumulative sum of a other list?
i tried it that way:
;;all temperatrue-values around the turtle saved in list
set temperature_values (list [(output-heat + 1)^ Freedom] of neighbors)
;;build cumulative value of temperatures and put each value in list
let tempsum 0
set tempsum_list []
foreach temperature_values
[set tempsum (tempsum + ? )
set tempsum_list fput tempsum tempsum_list
]
but it doesn't work. can anyone fix this problem? it says that "+ excepted a input but gets a list instead".
your code for a cumulative sum works (except that I think you need lput rather than fput. You can see it with this:
to test
let ll [1 2 3 4]
let tempsum 0
let tempsum_list []
foreach ll
[ set tempsum (tempsum + ? )
set tempsum_list lput tempsum tempsum_list
]
print tempsum_list
end
Did the error highlight the line set temperature_values (list [(output-heat + 1)^ Freedom] of neighbors)? Try putting a space after between ) and ^. NetLogo is picky about space around mathematical operators.
As Jen suggested, you can use foreach. Another nice approach is reduce:
to-report partial-sums [#lst]
set #lst (fput [0] #lst) ;;prepare for reduce
report butfirst reduce [lput (?2 + last ?1) ?1] #lst
end
Similar to Alan's solution (Just an update for the recent version of NetLogo that replaces ? with -> for anonymous procedures.)
to-report partial-sums [lst]
report butfirst reduce [[result-so-far next-item] -> lput (next-item + last
result-so-far) result-so-far] fput [0] lst
end
This is like Alan's solution, just abstracted a bit further. (Perhaps too far, depending on your taste! I like JenB's solution as well.)
Let's first define a thing like reduce, but that keeps all the intermediate results:
to-report scan [fn xs]
report reduce [lput (runresult fn ?2 last ?1) ?1]
(fput (list first xs) butfirst xs)
end
Now we can use it to compute partial sums:
observer> show scan task + [1 2 3 4 5]
observer: [1 3 6 10 15]
but we are also free to swap in a different operation:
observer> show scan task * [1 2 3 4 5]
observer: [1 2 6 24 120]