Permanent Choices in NetLogo - simulation

In this model, if certain conditions are met, farmers invest in their Rate of Production (RoP). If other conditions are met, they invest in their Standard of Living (SoL).
Currently, this is executed via several if statements within the To Invest procedure at each time step.
How can I make the courses of action permanent. For example, if the first farm at tick 2 meets the conditions to invest in RoP, that farm should continue to do so at each subsequent time step, not have the option at tick 3 to invest in SoL. How can I make this action permanent?
to invest
let p random 100
set excess-prev-tick farm-excess
if ( farm-excess > 0 and p <= 30 ) [
set farm-RoP ( farm-RoP + farm-excess )]
if ( farm-excess > 0 and p > 30 and SoL < SoL-max ) [
set SoL ( SoL + 0.1 )]
if ( farm-excess > 0 and p > 30 ) [
set farm-RoC ( farm-RoC + ( count patches in-radius farm-size * 2 ))]
if farm-excess < 0 and SoL >= SoL-min [
set SoL ( SoL - 0.05) ]
set farm-excess (farm-ROP - farm-RoC)
set RoExp ((farm-excess - excess-prev-tick) / (excess-prev-tick))
end

The easiest way is to create a variable for each farmer (using a farmers-own statement) that is initialised as "undecided" and then becomes either "production" or "living" when the condition is met for one of them. You should then organise your invest code to have different calculations for different subgroups of farmers (so something like ask farmers with [invest-type = "undecided"][ <do stuff> ]

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.

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.

Multi-scale landscape in Netlogo (small patches and larger patch groupings)

I am trying to represent a multi-scale environment where I have large patches that represent high-value areas in the landscape and smaller patches that have local information. E.g. I want to have snow data at a 1km^2 scale but I also want to have larger patches (9km^2) that summarize large-scale information. Each of my large patches has a variable value that is different from its neighbors but the variable value may be repeated throughout the landscape in other patches. I am looking for the most straightforward way for my turtles to identify the difference between the large-scale patches. I had thought of creating patch-sets but I am not sure how to get around the issue of variable values repeating in different patches. Any help is much appreciated.
EDIT: I have created a raster with equal patch structure as the large-scale raster and assigned "patch-id's" using this, so that there is no longer variable repetition in the world. I am still struggling with getting turtles to identify these larger patches as grouped entities.
You commented on my first answer
My main issue is that I need to run a "find max-one-of
neigboring-large-patches [large-scale-variable]" so I need my turtles
to understand what the neighboring large-patches are and be able to
read them as units, if that makes sense. I can't quite figure out how
to incorporate that into your answer, any thoughts?
Here's how to do that. This code is fast and sloppy but it illustrates the point.
Let the large-regions have x and y values, generated during creation. Basically, these store the column and row numbers of the grid of large regions that covers the viewport.
breed [ large-regions large-region ]
large-regions-own [
terrain
region-color
population
x
y
]
Then, conceptually, the neighbors of a region will have x and y values within +/- 1 of the region's x and y values, so you can identify them that way.
To simplify coding at the expense of space, when I generated the regions I also stored the unique identifier (who) of that region and its x and y values into every patch in that region, in variables lrx and lry.
patches-own [
large-region-who
lrx
lry
]
The heart of finding the neighboring large-region with the max value of population as you requested follows. I coded this for speed in debugging , not for elegance, so it can be greatly cleaned up. The full source code has many print statements that effectively comment each step in solving your requested search.
This looks around (patch 0 0), finds the info on the large region's x and y from that patch, generates an agent-set of large-regions with nearby x and y values, does a max [population] search on that set to extract the region with the highest population. It also colors the asking patch black, the local large-region blue, and the maximum population neighbor red.
It mostly works -- the large regions are offset by one patch from where they should be -- but this illustrates the point. Run setup and go and see for yourself.
Here's the (ugly) code to play with. Interesting problem. You can easily extend this to small regions as well, and have both working at the same time. Enjoy!
globals [
large-region-size
]
breed [ large-regions large-region ]
large-regions-own [
terrain
region-color
population
x
y
]
patches-own [
large-region-who
lrx
lry
]
to setup
clear-all
set large-region-size 5
no-display
make-large-regions
ask patches [ set pcolor white ]
display
ask large-regions [ set hidden? true]
print (word " hilly region count: " count large-regions with [terrain = "hilly"] )
;; print (word " deep snow count: " count small-regions with [snow-cover > 75])
reset-ticks
end
to go
ask patches [ set pcolor white]
; ;; lets examine the large-regions
; print " large region xvals "
; let xvals [ ]
; ask large-regions [ set xvals fput x xvals ]
; set xvals remove-duplicates xvals
; show xvals
; print " "
; print " patch lrx values: "
; set xvals [ ]
; ask patches [ set xvals fput lrx xvals ]
; set xvals remove-duplicates xvals
; show xvals
; print "========================================="
print " let's examine large-regions around the patch at 0 0 "
let x-spot 0
let y-spot 0
print ( word " looking for large-regions with max population bordering the following patch " x-spot " " y-spot)
; ask n-of 1 patches [ set x-spot pxcor set y-spot pycor print (word "selected patch " x-spot ", " y-spot )]
let home-who [ large-region-who] of patch x-spot y-spot
print (word "home-region-who is " home-who)
print " "
;; thinking ahead, we have coded the x and y values of the large region around us directly into the patch variables
let home-x [ lrx ] of patch x-spot y-spot
let home-y [ lry ] of patch x-spot y-spot
print (word "this blue home region has x=" home-x " and y=" home-y )
ask patches with [lrx = home-x and lry = home-y] [ set pcolor blue ]
ask patch x-spot y-spot [ set pcolor black ]
let home-neighbor-set large-regions with [
( x >= ( home-x - 1 )) and ( x <= ( home-x + 1) ) and (y >= ( home-y - 1 ) ) and ( y <= ( home-y + 1 ) ) ]
print "count of home-neighbor-set is "
print count large-regions with [
( x >= ( home-x - 1 )) and ( x <= ( home-x + 1) ) and (y >= ( home-y - 1 ) ) and ( y <= ( home-y + 1) ) ]
print " "
print "here is that set "
show home-neighbor-set
print " "
ask home-neighbor-set [ print (word "Large region with who = " who " has population " population )]
let big-boy max-one-of home-neighbor-set [ population]
show big-boy
print ( word " Neighboring red large-region with largest population is " big-boy " with population " [population] of big-boy )
let bbx 0
let bby 0
let bwho 0
ask big-boy [ set bbx x set bby y set bwho who]
ask patches with [lrx = bbx and lry = bby] [ set pcolor red ]
tick
end
to make-large-regions ;; for testing
let px min-pxcor
let py min-pycor
let region-id -1 ;; missing
let mysize large-region-size
let stopper 0
while [px < max-pxcor] [
while [py < max-pycor] [
if stopper > 300 [ stop ] ;; stops making large regions
set stopper stopper + 1
let xcode round ( ( px + 1) / 5)
let ycode round ( ( py + 1) / 5)
;; make a new region
let decolor one-of [ red blue yellow green ]
create-large-regions 1 [
set terrain one-of ["hilly" "flat" "mountain" "water" "swamp"]
set region-id who
set population random 1000
set x xcode
set y ycode
set region-color decolor
]
;; large region is defined, update the patches in that region
ask patches with [ (abs (pxcor - px) < (mysize / 2) )
and (abs (pycor - py) < (mysize / 2) )] [
set pcolor decolor
set large-region-who region-id
set lrx xcode
set lry ycode
]
set py py + mysize
]
if py > max-pycor [
set py min-pycor
set px px + mysize]
]
end
This may not be the best way, but I think it would work. You could let regions own several variables, such as "large-region-unique-id" and "small-region-unique-id" and make one pass where you set all these variables. Then a turtle would only have to look at a patch to know what small and large region it is part of.
If you also made a breed of agents called "regions" (say), you could have regions-own variables and have a unique-region-id. ( actually, the agent's who number would work
for that)
That should encode the information so that a moving turtle could easily look up relevant information.
breed [ large-regions large-region ]
large-regions-own [
terrain-type
large-scale-variables
...
(who)
]
breed [ small-regions small-region ]
small-regions-own [
snow-cover
small-scale-variables
...
(who)
]
patches-own [
large-scale-region-who ;; the id (who) of the large-scale-region the patch is in
small-scale-region-who ;; the id (who) of the small-scale-region the patch is in
...
]
Then a turtle could ask a patch for the relevant who information and use it to look up data from the larger "patches".
Here's what that might look like
print (word " hilly region count: " count large-regions with [terrain = "hilly"] )
print (word " deep snow count: " count small-regions with [snow-cover > 75])
;; how about highlighting patches that are mountainous with deep snow?
no-display
ask patches [
set terrain-type ""
set my-snow-cover -1
set srw small-scale-region-who
if srw > 0 [set my-snow-cover [snow-cover] of (small-region srw)]
set lrw large-scale-region-who
if lrw > 0
[ set terrain-type [terrain] of large-region lrw]
if-else (terrain-type = "mountain") and (my-snow-cover > 75)
[ set pcolor white ]
[ set pcolor black ]
]
display
print " The mountainous terrain with deep snow-cover is shown in white "

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

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