How to create a sequential counter in NetLogo 6.2? - netlogo

I would like to know if there is any way to implement a sequential counter without using a list by intervals. I'm trying to implement the following: at the end of each tick is counting the population size (NFinal). And then, we would check the constancy of the population, through a subtraction (the logical test would be the result of this subtraction is equal to zero during 3 consecutive ticks?).
For example:
NFinal of tick 0 - NFinal of tick 1 = 0
NFinal of tick 1 - NFinal of tick 2 = 0
NFinal of tick 2 - NFinal of tick 3 = 0
If this is the scenario (with 3 sequential values ​​equal to zero), the simulation will stop.
However, if it is in the scenario:
NFinal of tick 0 - NFinal of tick 1 = 0
NFinal of tick 1 - NFinal of tick 2 = 0
NFinal of tick 2 - NFinal of tick 3 = 2
The simulation does not stop (since it did not have 3 zero values ​​in sequence) and therefore would reset the counter to continue the simulation.
However what I managed to implement was by intervals using list. I don't know if it's the best way. Well, every time I use the list my model is getting slower. Is there a simpler way to implement this?
Thanks in advance!
Attempt below:
globals [ StabilityList ConstanceInterval ]
to go
if ConstanceInterval = 0 [ stop ]
end
to StabilityCheckerProc
set StabilityList lput 1 StabilityList ;; 1 = NFinal
let i 3 ;;
if length StabilityList >= i
[
let t1 last StabilityList
let start ( length StabilityList - i )
let t0 item start StabilityList
set ConstanceInterval abs ( t1 - t0 )
]
set StabilityList get-last i StabilityList
end
to-report get-last [ num lst ]
let b length lst
let a b - num
report sublist lst ( ifelse-value ( a < 0 ) [ 0 ] [ a ] ) b
end

You could use a counter to track the number of occurrences in a row, such that if your condition is satisfied you increase the counter, and if it is not you reset the counter. For example:
globals [ zero-tracker ]
to setup
ca
reset-ticks
end
to go
let variable-placeholder random 5
ifelse variable-placeholder = 0 [
; If a zero is recorded (eg, the result of your subtraction operation,
; increase the zero-tracker by one
set zero-tracker zero-tracker + 1
] [
; If anything BUT a zero is recorded, reset the zero-tracker
set zero-tracker 0
]
tick
if zero-tracker = 3 [
stop
]
end

Luke's answer is the answer.
But, if for any reason you did have a problem that needed to look at the last X things, and a counter was not going to work, you could use a list, but keep it at length X.
;; in setup, initialize the list with 'memory-size' items
set memory map [ -> 0] range 0 memory-size
;; in go, add a new memory to the list, and drop an old memory
set memory but-first lput value memory
;; then do what you must to examine the memories
< that code here >
Still slower than using a counter, but probably faster than accumulating and taking sections from an ever-growing list of values.
If you do need to maintain an ever-growing list of values, you might still maintain this smaller list.
Finally, even when using the ever-growing list of values, it would be fewer operations to take the sublist off the front of the list:
;; add new memory to front of list
set memory fput value memory
;; get last three memories from front of list
let last-three sublist memory 0 3 ;; no math or length needed
As always, test any assertion that something might be faster.

Related

How to implement a timer for each turtle in netlogo

I am trying to implement a timer for each turtle in Netlogo
so I can take the minimum value, maximum and average time taken for each turtle.
Can anyone help
You haven't said what you actually want timed (or given any code attempt). Any time you need a turtle to remember anything from one tick to the next, you need a variable. The simplest code for a timer is to have a variable that you set to the current value of ticks when the process starts and subtract that start time from the current value of ticks when the process stops. Here is a complete model example:
turtles-own
[ start-time
time-taken
]
to setup
clear-all
create-turtles 20
[ set start-time 2 + random 10
set time-taken -1
]
reset-ticks
end
to go
let movers turtles with [time-taken = -1 and start-time <= ticks]
ask movers
[ set heading random 360
forward 1 + random 3
if random-float 1 < 0.05 [ set time-taken ticks - start-time ]
]
tick
end
And check out the new Time extension if you want your timers to use real time units (seconds, minutes, years...) and have non-integer values.
https://github.com/NetLogo/Time-Extension
Look at primitives such as time:difference-between
For example, you could do this coding that flags the turtle you want to monitor and increments the flag variable when an event occurs. You can then monitor it in the BehaviorSpace and analyses the results output in a csv file. For example, the following codes:
globals [ID]
turtles-own [special-turtle]
to create-turtle
crt 1 [
setxy min-pxcor 0
set heading 90
set special-turtle false
set ID who]
end
to go
;omitted
special-turtles
tick
end
to special-turtles
ask turtles-on patch 0 0 [set ID who]
ask max-one-of turtles [who] [set special-turtle true]
ask turtles with [special-turtle = true][set special-turtle (special-turtle + 1)]
end
I think there is something that none of the previous answers considered: the way you implement your timer depends on how you want to use the measurement.
1 - If you want to read the measurement only after the measurement is completed
The expression "after the measurement is completed" can mean both that you want to read it at some point later during the model, or maybe even just from some model's output.
The approach I'd take in this case is similar to what JenB suggested, but I believe you can put it a bit simpler because here I only use one extra turtle variable (apart from my-variable, that is there only to represent something that you already have in your model):
turtles-own [
my-variable ; This represents something you have in your model, to be used as a condition for the timer
my-timer
]
to setup
clear-all
reset-ticks
create-turtles 10
end
to go
; Here you have your normal code. When you need, just include
; 'start-timer' and 'stop-timer'. For simplicity, let's
; say you want to count how long does each turtle take
; to get from a value of 1 to a value of 5 for my-variable.
; You can just do:
ask turtles [
if (random 10 < 2) [
set my-variable (my-variable + 1)
]
if (my-variable = 1) [
start-timer
]
if (my-variable = 5) [
stop-timer
type "I am turtle " type who type " and it took me " type my-timer print " ticks."
die
]
]
tick
if (not any? turtles) [stop]
end
to start-timer
set my-timer ticks
end
to stop-timer
set my-timer (ticks - my-timer)
end
Note that most of the code is there only to make a full reproducible example, but the actual implementation only consists of my-timer, to start-timer and to stop-timer.
You can take this approach because the hypothesis here is that you will be interested in reading the measurement only after to stop-timer happened.
Otherwise, see point 2.
2 - If you want to be able to read the measurement at any moment during the simulation
In this case, you need to make the timer progress as time progresses (as opposed to point 1, where you could just take the initial and final time, and make the difference between the two).
I guess the easiest way to do this is to conditionally increment the timer every time there is a tick.
Taking the same example as before, it would be something like:
turtles-own [
my-variable ; This represents something you have in your model, to be used as a condition for the timer
timer-active?
my-timer
]
to setup
clear-all
reset-ticks
create-turtles 10 [
set timer-active? FALSE
]
end
to go
ask turtles [
if (random 10 < 2) [
set my-variable (my-variable + 1)
]
if (my-variable = 1) [
set timer-active? TRUE
]
if (my-variable = 5) [
set timer-active? FALSE
]
]
tick
ask turtles with [timer-active?] [
set my-timer (my-timer + 1)
]
if (count turtles with [my-variable < 5] = 0) [stop]
end
This way, you will be able to see at any moment what is the current value of my-timer for each turtle.

While condition should check whether the sum of two variables is below a threshold or not

I am working on a model in which my agents should drive to work. However, their reach is limited that's why I want to use a WHILE function to check whether the distance driven to the destination (distance-to-work) plus the distance driven at the destination (e.g. using their own car for a delivery service = distance-to-work) is below a certain threshold (here, 130 km). The idea is that the agents can drive to and return from work if they only drive up to 130 km, that is, the sum of distance-to-work and distance-at-work should be less than 130. Otherwise, they would run out of gasoline.
The distances are drawn according to a probability distribution. The probability for each variable is called chance_distance_to_work and chance_distance_from_work, respectively. E.g. with a probability of 3% they drive 2km to work, with a probability of 8%, they drive 4km to work, etc. The same goes for the distance driven at work. I intend to derive the distances via a nested ifelse-statement.
I would like to repeat the "drawing" of my chance_distance_to/at_work variable until the sum of both variables (distance-to/at-work) is 130 or less, which allows them to come back to their home place.
turtle-own [
distance-to-work
distance-at-work
]
to setup-driving-pattern
ask full-time-employees [
; the loop should continue until the sum of both, distance-to-work
; and distance-at-work is 130 or less
while [distance-to-work + distance-at-work >= 131] [
; I created two variables for the chance of each variable,
; in order to assign a certain number (km). This variable
; should draw a random number between 0 and 99. According
; to this number (or probability) the respective
, distance-to-work or distance-at-work is drawn.
let chance_distance_at_work random 100
let chance_distance_to_work random 100
; here is a nested ifelse statement which continues until 100%,
; but this is just an example
ifelse chance_distance_to_work < 3 [set distance-to-work 2 ] [
ifelse chance_distance_to_work < 8 [set distance-to-work 4 ] ... ]
ifelse chance_distance_at_work < 4 [set distance-at-work 1 ] [
ifelse chance_distance_at_work < 12 [set distance-at-work 2 ] ... ]
]
]
end
I guess something is wrong with the addition within the WHILE function. Because without the while function each turtle (here, full-time-employee) gets his own variable for distance-to-work and distance-at-work. Moreover, if the condition or the reporter does not state [distance-to-work + distance-at-work >= 131], but [distance-to-work + distance-at-work < 131] instead, it works. So the WHILE function returns the distance-to-work and distance-at-work if the sum is bigger than 130. But if I just switch the sign, it does not work anymore and the assigned values for both variables are always 0, so the default value.
I can set up both variables independently, i.e. I can obtain a value for each variable. However, if I now want to combine both variables and check whether their sum is below a certain threshold (e.g. 130), then both variables are always determined as 0.
Thanks a lot. I appreciate your help!
I do not understand the problem, but my reply is too long for a "comment" so I will put it here as "an answer".
First, there is no closing bracket for this open one: "ask full-time-employees [ " so I will assume you wanted one more "]" at the very end.
But, you do not have the correct syntax for the "while" statement -- it must have brackets around both the test and the commands to run if the test passes. That is, it always must look like this:
while [ ] [ ]
You only have this:
while [ ]
So the editor will give you an error: "While expected two inputs, a TRUE/FALSE block and a command block."
Again, I assume you meant for the rest of the code to be inside the WHILE loop.
Since I don't see a "let" statement for them, I tried to assume that distance-to-work and distance-at-work are global variables. ( Please post all your code next time so we do not need to guess! ) But, if they are meant to be global variables, your code will fail, because they will be initialized to zero, so the WHILE test will always fail.
Anyway, it makes no sense to me that you are testing whether the sum of these is greater than 130 and if it is, then keep driving. I am going to assume you want to STOP driving when the total distance driven is over 130 km.
The the WHILE test will be TRUE for the first employee, but these numbers will increase until finally the WHILE test will fail, and the employee will stop driving. But nothing you have written will RESET these variables to zero, so the WHILE test will fail for every other driver. Not good.
So, these need to be local variables, not global variables, and they need to be declared ( by a "let" statement ) and initialized to zero inside the "ask full-time-employees [ ]
block and near the start of that block.
Next, I do not understand what you are trying to do, where you have tests like this:
ifelse chance_distance_to_work < 3 [set distance-to-work 2 ] [ ...]
WHY would you do such a thing? I would think that what you want to do is simply add the new chance_distance_to_work to the old running total "distance-to-work", then add the new chance_distance_at_work to the old running total "distance-at-work", and then end the block. Then you are ending the block with (distance-at-work + distance-at-work) equal to the total distance driven so far, and you can test that in the next pass of the WHILE loop. Right?
I will assume that is correct, and here is the code with those changes made in it. This code will run. I put in many "print" statements to show what it is doing. I hope this answers your question.
Here's the code and sample output it generates.
breed [full-time-employees full-time-employee]
to setup
clear-all
create-full-time-employees 2 ;; 2 is enough for testing
reset-ticks
end
to go
ask full-time-employees [
print word "Analyzing employee number " who
let distance-to-work 0 ;; this is a running sum
let distance-at-work 0 ;; this is a running sum
let total-distance-so-far 0 ;; this will be distance-to-work + distance-at-work
; the loop should continue until the sum of both, distance-to-work and distance-at-work is 131 or more
while [total-distance-so-far <= 130] [
; drive one more day
let chance-distance-at-work random 50
let chance-distance-to-work random 50
print word "......chance-distance-to-work today = " chance-distance-to-work
print word "......chance-distance-at-work today = " chance-distance-at-work
;; calculate the total distance driven so far
set distance-to-work ( distance-to-work + chance-distance-to-work)
set distance-at-work ( distance-at-work + chance-distance-at-work)
set total-distance-so-far distance-to-work + distance-at-work
print word "...At the end of this pass of the WHILE loop, total distance so far = " total-distance-so-far
]
print word "......After we exit the WHILE loop, total distance so far = " total-distance-so-far
print word " ----------- done with employee " who
print " "
]
tick
end
and sample output:
Analyzing employee number 0 ......chance-distance-to-work today = 15
......chance-distance-at-work today = 39 ...At the end of this pass
of the WHILE loop, total distance so far = 54
......chance-distance-to-work today = 8 ......chance-distance-at-work
today = 37 ...At the end of this pass of the WHILE loop, total
distance so far = 99 ......chance-distance-to-work today = 10
......chance-distance-at-work today = 35 ...At the end of this pass
of the WHILE loop, total distance so far = 144 ......After we exit
the WHILE loop, total distance so far = 144
----------- done with employee 0 ... Analyzing employee number 1 ......chance-distance-to-work today = 42
......chance-distance-at-work today = 11 ...At the end of this pass
of the WHILE loop, total distance so far = 53
......chance-distance-to-work today = 23
......chance-distance-at-work today = 14 ...At the end of this pass
of the WHILE loop, total distance so far = 90
......chance-distance-to-work today = 17
......chance-distance-at-work today = 31 ...At the end of this pass
of the WHILE loop, total distance so far = 138 ......After we exit
the WHILE loop, total distance so far = 138
----------- done with employee 1
I don't know if that is the usual way to handle these questions but I found the error I was running into the entire time and I want to share it in case someone else might run into a similar problem.
So I wanted to check whether the reporter [distance-to-work + distance-at-work < 131] was met or not. If reporter reports false, exit the loop. Otherwise run commands and repeat. The problem was that the default value of distance-to-work and the default value of distance-at-work is 0. Hence, by default the reporter reports false and exits the loop without even running the commands once.
I first have to define the default value of the variables in such way, that the reporter reports true and hence, the commands are run. So, the revised version is below:
ask full-time-employees [
set distance-to-work 100
set distance-at-work 100
while [distance-to-work + distance-at-work > 131] [
let chance_distance_to_work random 100
let chance_distance_at_work random 100
ifelse chance_distance_to_work < 3 [set distance-to-work 2 ] [
ifelse chance_distance_to_work < 8 [set distance-to-work 4 ] ... ]
ifelse chance_distance_at_work < 4 [set distance-at-work 1 ] [
ifelse chance_distance_at_work < 12 [set distance-at-work 2 ] ... ]
]
]

How to fix "Nothing named ? has been defined" error in NetLogo 6.0.4

I downloaded the modified random clusters code for generating neutral landscape models using the Millington's version of the modified random clusters approach in the NetLogo modeling commons. When I click the "generate-landscape" button, the "fill-landscape" procedure in the code causes a "Nothing named ? has been defined" error.
When I created the attached interface image and attempted to run the adjoining code below. The problem seems to be related to the question mark in the "occurrences" report function. The reduce function is not working as intended. Is there a work around for this? See interface, then code below:
ifelse ( any? neighbours with [ cluster != nobody ] ) ;; check if there are any assigned patches in neighbourhood
[
let covers []
ask neighbours with [ cluster != nobody ]
[
set covers fput cover covers ;;ask neighbours to add their covers to the list
]
let unique-covers remove-duplicates covers ;;create a list of unique covers
let max-cover-count -1 ;the number of neighbours with the maximum cover
let max-cover -1 ;the maximum cover
ifelse(length unique-covers > 1)
[
;if there is more than one unique-cover
foreach unique-covers ;for each of the unique covers
[
let occ occurrences ? covers ;count how many neighbours had this cover
ifelse(occ > max-cover-count) ;if the count is greater than the current maximum count
[
set max-cover ? ;set this as the dominant cover
set max-cover-count occ ;update the current maximum count
;---------------
to-report occurrences [x the-list]
report reduce
[ifelse-value (?2 = x) [?1 + 1] [?1]] (fput 0 the-list)
end
;---------------
The code is suppose to generate a neutral landscape model using the modified random clusters approach developed by Saura and Martinez-Millan (2000). However, the error "Nothing named ? has been defined" error the code from running smoothly. Looking forward to thoughts ...
The old ? syntax from NetLogo 5.x was replaced with the new -> syntax in NetLogo 6. See https://ccl.northwestern.edu/netlogo/docs/programming.html#anonymous-procedures
So, for example, in NetLogo 5, you would write:
foreach [0 1 2 3] [
print ?
]
in NetLogo 6, you write:
foreach [0 1 2 3] [ x ->
print x
]
A combination of Bryan's answer (first procedure) and the NetLogo Dictionary (second procedure) gives you the following. The comments indicate the new bits. Not tested.
ifelse ( any? neighbours with [ cluster != nobody ] )
[ let covers []
ask neighbours with [ cluster != nobody ]
[ set covers fput cover covers
]
let unique-covers remove-duplicates covers
let max-cover-count - 1 ; added a space around subtraction
let max-cover - 1 ; more spacing
ifelse(length unique-covers > 1)
[ foreach unique-covers
[ this-cover -> ; here's the new bit, calling ? 'this-cover'
let occ occurrences this-cover covers ; passes to the occurrences procedure
ifelse(occ > max-cover-count)
[ set max-cover this-cover ; using the name this-cover again
set max-cover-count occ
And for occurrences, you can take the procedure directly from the NetLogo Dictionary reduce example
to-report occurrences [#x #the-list]
report reduce
[ [occurrence-count next-item] -> ifelse-value (next-item = #x)
[occurrence-count + 1] [occurrence-count] ] (fput 0 #the-list)
end

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.

Subtracting element of ith position from element at (i + 1)th position of any list in netlogo

I want to create a list of count values of some variable (tot-turtles) increasing with each tick. I tried the below code but all time list is having single element of length 1. neither i is getting incremented. please correct me.
set tot-turtles count turtles
to go
let mylist [ ]
set mylist lput tot-turtles mylist ; show mylist
set i 1
foreach mylist [ ; print ? ;show i
set x ? - i ; print x
set i (i + 1) ;show i
]
end
I want to subtract elements of list in the following fashion where the length of list depends on the number of simulation run or till simulation ends, then
i need subtraction of element as element at (i + 1)th - element at ith position till the end of the list.
In the above code i is 1 then increments by 1 ie 2 and then continue to 1 2 1 2 1 2. mylsit always shows single element. Confused with "?" , it gives element of current position if i am not wrong, but how we know the current position?
Please help me out of these doubts and code. thanks a lot.
Thank you sir, yes i was doing mistake with local and global variable i checkd it later. and the thing i wanted is as below.
to setup
set mylist [ 0]
set item-difference 0
end
to go
set tot-turtles count tutles set
mylist lput tot-turtles mylist
let _n (length mylist)
set item-difference (( item ( _n - 1 ) mylist - item ( _n - 2 ) mylist )
end
I hope you got Allan sir.
It's a bit difficult to tell what you are after, but it seems you are using a local variable when you want a global variable. See if this offers some help:
globals [mylist]
to setup
ca
set mylist []
crt 10
end
to go
crt 1
set mylist lput (count turtles) mylist ; show mylist
end
to test
let _n (length mylist)
(foreach mylist n-values _n [? + 1] [
print ?1 - ?2
])
end