Why Netlogo `range` command with step behaves different below 1 - netlogo

I would like Netlogo to make a range with steps below 1, but it does a different number of items than using the start number above 1.
For example,
show (range (0.75 - 0.20) (0.75 - 0.15) 0.05)
[0.55]
but,
show (range (1.75 - 0.20) (1.75 - 0.15) 0.05)
[1.55 1.6]
Is there any way to make that (range (0.75 - 0.20) (0.75 - 0.15) 0.05) gives also two values
[0.55 0.6].?

Netlogo uses a precision internally that mekes operation like this:
0.60 >= (0.55 + 0.05)
false
and
1.60 >= (1.55 + 0.05)
true
I do not know if this is a bug of Netlogo, but the first logic result is odd because it should give true not false.
A solution is a procedure to make range lists.
to-report my-range [ini fin stp]
let prec 2
ifelse fin >= (precision (ini + stp) prec) [
let mr (list ini)
let lv ((precision ((fin - ini)/ stp) 1) )
let val 0
repeat lv [
set val (last mr)
set mr (lput (precision (val + stp) prec) mr)
]
report mr
] [
report ini
]
end
Now
show my-range 0.55 0.60 0.05
[0.55 0.6]

Related

Is there a simple way to code for a sequence of multiples of ticks in netlogo?

How do I have a model decrease a variable by some increment every x ticks, without simply coding a long list? It seems like there should be a way to use multiples of ticks, e.g decrease the variable every 20n ticks, where n = 1, 2, 3,..., but I couldn't think of how that would work, so I just created a list.
For example, in the code below, I am decreasing the variable octopamine-level by 1 unit every 20 ticks past first-leader-tick.
if (ticks - first-leader-tick = 20) or (ticks - first-leader-tick = 40) or (ticks - first-leader-tick = 60) or (ticks - first-leader-tick = 80) or (ticks - first-leader-tick = 100) or (ticks - first-leader-tick = 120) or (ticks - first-leader-tick = 140) or (ticks - first-leader-tick = 160) or (ticks - first-leader-tick = 180)
[set octopamine-level octopamine-level - 1]
However, I am planning on using a much larger variable, which would require a ridiculously long list, so a cleaner method would be very helpful.
Thanks!
Simple approach #1
You can use a reminder for the next time that the value needs to be updated:
globals [
next-update
octopamine-level
]
to setup
clear-all
reset-ticks
set octopamine-level 10
type "initial level of octopamine: " print octopamine-level
set next-update "none" ; This is needed because, otherwise, the first iteration (i.e. where
; 'ticks = 0') would always satisfy the 'if (ticks = next-update)'
; condition. Doing 'set next-update - 1' would work too, depending on
; which approach you find more relevant and/or elegant.
end
to go
; With this first block of commands I'm just randomly choosing the
; initial tick for starting the reduction.
if (octopamine-level = 10) AND (random 100 < 1) [
set octopamine-level octopamine-level - 1
set next-update ticks + 20
type "ticks = " type ticks type ", octopamine = " type octopamine-level print ", reduction started"
]
if (ticks = next-update) [
set octopamine-level octopamine-level - 1
set next-update ticks + 20
type "ticks = " type ticks type ", octopamine = " print octopamine-level
]
if (octopamine-level = 0) [stop]
tick
end
Simple approach #2
If you also want to have the information more readily accessible about how long will it take until the next update / how long has passed since the last update, you can create a counter:
globals [
counter
counter-on? ; See comment to in 'to setup'.
octopamine-level
]
to setup
clear-all
reset-ticks
set octopamine-level 10
type "initial level of octopamine: " print octopamine-level
set counter "none"
set counter-on? FALSE ; This, together with the condition in which it is used, is needed
; because we cannot simply 'set counter "none"', as that will give
; a runtime error when executing 'set counter counter - 1' (and using
; 'if (is-number? counter) [set counter counter - 1]' doesn't look
; very nice to me).
; Note that you could get rid of all the 'counter-on?' thing and just
; do 'set counter -1' upon setup. This would work, but would also
; execute 'set counter counter - 1' at every tick, bringing 'counter'
; to always more negative numbers before the reduction actually starts -
; which I personally don't really like.
end
to go
; With this first block of commands I'm just randomly choosing the
; initial tick for starting the reduction.
if (octopamine-level = 10) AND (random 100 < 1) [
set counter-on? TRUE
set counter 20
set octopamine-level octopamine-level - 1
type "ticks = " type ticks type ", octopamine = " type octopamine-level print ", reduction started"
]
if (counter = 0) [
set octopamine-level octopamine-level - 1
set counter 20
type "ticks = " type ticks type ", octopamine = " print octopamine-level
]
if (octopamine-level = 0) [stop]
if (counter-on?) [
set counter counter - 1
]
tick
end
Another positive side of this approach is that it makes it simple to pause and resume the counter anytime you want if you ever need to, simply by using set counter-on? FALSE and set counter-on? TRUE.
Less simple approach
To take an approach that looks more similar to your line of thought (but more convoluted than the previous options), this kind of need can also be addressed by using remainders, and in NetLogo you can use remainder indeed (check here).
You can use the following routine to perform a command every 20 ticks.
if (remainder ticks 20 = remainder first-leader-tick 20) [
set octopamine-level octopamine-level - 1
]
Overall, performing the type of adjustments that I discussed for the other approaches earlier, it would look something like:
globals [
first-leader-tick
reduction-on?
octopamine-level
]
to setup
clear-all
reset-ticks
set octopamine-level 10
type "initial level of octopamine: " print octopamine-level
set reduction-on? FALSE
end
to go
; With this first block of commands I'm just randomly choosing the
; initial tick for starting the reduction.
if (octopamine-level = 10) AND (random 100 < 1) [
set reduction-on? TRUE
set first-leader-tick ticks
set octopamine-level octopamine-level - 1
type "ticks = " type ticks type ", octopamine = " type octopamine-level print ", reduction started"
]
if (reduction-on?) AND (ticks > first-leader-tick) AND (remainder ticks 20 = remainder first-leader-tick 20) [
set octopamine-level octopamine-level - 1
type "ticks = " type ticks type ", octopamine = " print octopamine-level
]
if (octopamine-level = 0) [stop]
tick
end
The (reduction-on?) condition is needed because otherwise tick 0 will always pass the test (in fact it is true that remainder 20 20 = remainder 0 20).
The (ticks > first-leader-tick) condition is needed because (remainder ticks 20 = remainder first-leader-tick 20) is true also when the reduction starts (i.e. when ticks = first-leader-tick), which would bring to execute twice set octopamine-level octopamine-level - 1 on the tick when the reduction starts (once in the first if-block and once in the second if-block).
Alternatively, if you want you can get rid of the (ticks > first-leader-tick) condition by either:
removing the set octopamine-level octopamine-level - 1 line from the first if-block;
bringing the second if-block (the one where remainders are evaluated) before the first if-block (the one where the reduction is initiated).
Very simply, you can use the MOD operator to do this.
MOD does a division, then returns the remainder.
This has the great side effect of always returning a number between 0 and one less than the divisor.
Even more simply: ticks MOD 20 always gives a number between 0 and 19. 100 mod 20 is 0. 119 mod 20 is 19. 120 mod 20 is zero again. See? Neat, right?
So you could do
If (ticks - first-leader-tick) mod 20 = 0
[
;; do the thing you do every 20 ticks.
]
Note that this will make it do the thing the first time, too. So adjust your logic accordingly.

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

Changing range of variables netlogo

I have a variable:
ask group [set means-one groupmeans + resources-agent ]
I want to ask netlogo to constrain the variable between 1 to 99.
How?
Just to simplify Alan's first answer to remove the if statements:
You could do:
ask group [set means-one (max (list 1 (min (list 99 groupmeans + resources-agent))) ]
Your question is not entirely clear. What do you mean by "change the range"? If you mean to clip extreme values, you can do it like this:
to-report clip [#x #min #max]
if (#x < #min) [report #min]
if (#x > #max) [report #max]
report #x
end
Then you can ask turtles [set means-one clip means-one 1 99]. Otoh, if you actually want to rescale all existing values linearly into your new range, you could do the following:
to rescale-all-means-one
let _newmin 1
let _newmax 99
let _newrange (_newmax - _newmin)
let _lst [means-one] of turtles
let _min min _lst
let _max max _lst
let _range (_max - _min)
ask turtles [
let _scale (means-one - _min) / _range
let _scaled (_newmin + _scale * _newrange)
set means-one _scaled
]
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]

Nested foreach in 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