i have the following breed in my model.
ants-own
[
hops
distance-gone
distance-to-go
target-node
current-node
]
the current node gets updated and stores the link of new node ( i want to store the different values of current-node in a list ).
i have the following code
set b lput current-node b
where this code iterates through a procedure n stores the node number using this command.
But i am getting the following error
LPUT expected input to be a list but got the turtle instead
how to store agents in a list?
Apparently your variable b contains a turtle, not a list. Did you initialize b to contain an empty list?
lput won't create a list from nothing. It can only add an item to an existing list.
Here's some code showing that lput works just fine for adding turtles to a list, as long as you have a list (perhaps empty) to begin with:
to test
crt 10
let b []
repeat 5 [
set b lput (one-of turtles) b
]
print b
end
when I run this in the Command Center, I see:
observer> test
[(turtle 3) (turtle 8) (turtle 8) (turtle 1) (turtle 3)]
Related
I'm not able to assign the first item value of a list to a turtle variable. For example? I have list3 that has 1 item, that is:
list3: [[5 2]]
I would like the first value of list 3 item 0 to be assigned to reproduction (ie 5) and the second value of list 3 item 0 to be assigned to metabolism (ie 2).
How can I do this?
Thanks in advance
globals [ ValidHabsItem ValidHabs ItemList3 ]
turtles-own [ profiles-habitat metabolism reproduction ]
to setup
let list1 ( list 2 )
let list2 ( list 5 )
let list3 ( reduce sentence ( map [ i -> map [ j -> list j i ] list2 ] list1 ) )
print ( word "list3: " list3 )
let n0 count turtles
let s length list3 * 10
while [ n0 < s ]
[
let c count patches
if c = 0 [ stop ]
ask one-of patches
[
sprout 1
[
set profiles-habitat item ValidHabsItem ValidHabs
set reproduction item ItemList3 list3 ;; list3: [[5 2]];; value 5
set metabolism item ItemList3 list3 ;; list3: [[5 2]];; value 2
]
]
]
set n0 count turtles
end
You can easily understand how to do this by playing in the Command Center and seeing how NetLogo responds to your calls to the list.
Just create a global variable in the Code tab, as globals [my-list], and then follow my statements in the Command Center:
observer> set my-list [[1 2 3] [4 5 6] [7 8 9]]
observer> print my-list
[[1 2 3] [4 5 6] [7 8 9]]
So here we just created a list whose items are other lists.
Therefore, we have:
observer> print first my-list
[1 2 3]
observer> print last my-list
[7 8 9]
observer> print item 1 my-list
[4 5 6]
This means that now, for NetLogo, the whole first my-list statement is equal to [1 2 3]; in other words, it is a list containing those numbers. So you can treat first my-list as any other list. For example, if you want to extract the second item from that list, you will simply do:
observer> print item 1 (first my-list)
2
The parentheses there are optional: they are useful to make the statement more readable to humans, reminding us that the whole first my-list is a list from which we are extracting the second item (i.e. the item with index 1). However, NetLogo does not really need that:
observer> print item 1 first my-list
2
Now you should be able to easily solve your problem, because your case is easier than this: your list3, which in your example is [[5 2]], only has one item in it. This means that first list3 is equal to last list3 which is equal to item 0 list3, all of them being [5 2].
So there you can do:
set reproduction first (first list3)
set metabolism last (first list3)
In general, you can apply this mechanisms to how many levels of nesting you wish.
For example:
observer> set my-list [[[1 2] [3 4]] [[5 6] [7 8]]]
observer> print my-list
[[[1 2] [3 4]] [[5 6] [7 8]]]
observer> print first my-list
[[1 2] [3 4]]
observer> print last (first my-list)
[3 4]
observer> print first (last (first my-list))
3
PS:
Note that, in your while loop, you need to include set n0 count turtles within the command block (as in while [condition] [commands]).
The way you have it now, set n0 count turtles is outside the command block of the loop and this means that the loop will go on forever, because it will never get to the point where n0 is updated and so n0 < s will always evaluate as true.
Also, note that saying
let c count patches
if c = 0 [ stop ]
makes no sense in NetLogo: every model will always have at least one patch, so you will never get to the point of having no patches.
Maybe you wanted to say something like if (count patches with [not any? turtles-here] = 0) [stop]? Just guessing, but here we are going off-topic
I have created an opinion dynamics model, that works just fine. But now I wanted to see, how the opinion of all of my turtles changes. So I created the reporter "report [opinion] of turtles". When I put this in behaviorspace I get wildly jumping results that do not correspond with what I observe. If I test this with individual turtles like "report [opinion] of turtle 0", I get the smooth curve progression that I expected to see.
Does anyone know why this is happening? I would find it rather unwieldy, if I had to put every turtle individually in my behaviorspace, because I have sliding Agentsnumbers.
You can let each turtle have a list variable, at the beginning of which each turtle will record its ID. At every step, each turtle will append its opinion value.
Then you can have a global variable, which you will use as a list of lists, to which at the end of the simulation each turtle will append its own list.
In BheaviorSpace, you will only need to use one reporter (the list of lists) at the end of each experiment's run.
See below for a working example:
globals [
results
]
turtles-own [
opinion
my-list
]
to setup
clear-all
reset-ticks
set results (list)
create-turtles 3 [
set opinion random 10
set my-list list self opinion
]
end
to go
if (ticks = 5) [
ask turtles [
set results lput my-list results
]
stop
]
ask turtles [
set opinion opinion + 1
set my-list lput opinion my-list
]
tick
end
At the end of each run, the results reporter will look like:
[[(turtle 2) 3 4 5 6 7 8] [(turtle 0) 0 1 2 3 4 5] [(turtle 1) 5 6 7 8 9 10]]
Note that, this way, the lists in results will always be in random order.
If you're interested in having them ordered according to some criterion, you can do it.
The example below changes the if (ticks = 5) statement to order results according to turtles' ID, but you can just use sort on whatever characteristic you're interested in.
if (ticks = 5) [
let sorted-turtles sort turtles
foreach sorted-turtles [this-turtle -> ask this-turtle [set results lput my-list results]]
stop
]
Following the answer provided by an user to this question: Count number of occurrences in a list from same turtle, I tried to use what he suggested to filter both items and turtles as follows:
show sum map [t -> length filter [a -> item 1 a = turtle 3] [ all-archives ]] of all-turtles
The code above should count how many times item 1 created by turtle 3 is included in the lists (all-archives) of all turtles (all-turtles).
However, I have got the following error from the formula above:
ERROR: Expected closing bracket
(at the second "a").
I am sure that there is still a syntax error in what I wrote, but I have not found any example using two parameters to be filtered.
You do have a misplaced ]. Sometimes it is easier to break these long commands into pieces. The following code sets up a test by having two turtles put two entries in a given number of other turtles archives, as well as their own. It then does the counting in pieces, and finally puts those pieces together in a single command. In your question, you use "all-turtles", but that is simply turtles in NetLogo. The last command looks only at a random subset of turtles.
turtles-own [ archive ]
to test
clear-all
create-turtles 100 [
set archive []
]
ask turtle 3 [
let archive-entry list "at home" self
set archive fput archive-entry archive
ask n-of 30 other turtles [ set archive fput archive-entry archive ]
set archive-entry list "not at home" self
set archive fput archive-entry archive
ask n-of 40 other turtles [ set archive fput archive-entry archive ]
]
ask turtle 4 [
let archive-entry list "at home" self
set archive fput archive-entry archive
ask n-of 20 other turtles [ set archive fput archive-entry archive ]
set archive-entry list "not at home" self
set archive fput archive-entry archive
ask n-of 50 other turtles [ set archive fput archive-entry archive ]
]
; get a list of all archives.
let list-of-all-archives [archive] of turtles
; make a list of the number of occurrences we are looking for in each archive.
let list-of-count-in-each-archive map [t -> length filter [a -> item 0 a = "at home" and item 1 a = turtle 3] t] list-of-all-archives
; sum up the number of occurences across all archives.
show sum list-of-count-in-each-archive
show sum map [t -> length filter [a -> item 0 a = "not at home" and item 1 a = turtle 3] t] [archive] of turtles
show sum map [t -> length filter [a -> item 0 a = "at home" and item 1 a = turtle 4] t] [archive] of turtles
show sum map [t -> length filter [a -> item 0 a = "not at home" and item 1 a = turtle 4] t] [archive] of turtles
show sum map [t -> length filter [a -> item 0 a = "not at home" and item 1 a = turtle 4] t] [archive] of n-of 50 turtles
end
A toy example. There are two groups of people: A and B. Only A can say "hello" to people B. People walk around the world and meet each other. When people A meet people B, they say hello to them. Each person A record who was said hello to and the tick when that occurred. They cannot say hello to the same person until five new ticks happen. The procedures below only apply to people A.
Each time a person A say hello to a person B I define:
set tick-last-greeting lput ticks tick-last-greeting
set previous-person-b-greeted lput selected-person-b previous-person-b-greeted
Before the say-hello procedure happens again:
if (length tick-last-greeting != [] and previous-person-b-greeted != []) [
; wait 5 ticks
set temp (map [ticks - ? > 5] tick-last-greeting)
; filter the list, I don't know if there is a better way to do this
set previous-person-b-greeted (map last filter [first ? = false] (map list temp previous-person-b-greeted))
set tick-last-greeting (map last filter [first ? = false] (map list temp tick-last-greeting))
]
So, I get a list of people B that shouldn't be greeted by a person A but until five ticks happen. Here is my key problem: how to define an agentset that excludes the agents of the list previous-person-b-greeted.
set potential-persons-b targets-on (patch-set neighbors patch-here)
if (previous-person-b-greeted > 0) [
; Here, I get an error as expected
let who-previous-person-b [who] of previous-person-b-greeted
set potential-persons potential-persons with [who != who-previous-person-b]
]
A possible solution: transform the list previous-person-b-greeted into an agentset (I don't know if there is simple way to do this).
Any ideas?
To transform a list of agents into an agentset, use turtle-set or patch-set or link-set. So e.g.:
observer> create-turtles 5
observer> let mylist (list turtle 0 turtle 2 turtle 4) print turtle-set mylist
(agentset, 3 turtles)
I will assume that you're not using specific breeds for people A or people B.
Perhaps you could try using breeds, for example:
breed [personA peopleA]
breed [personB peopleB]
Will define 2 different agentsets and then you can use the <breeds>-own statement to define a list of recently greeted people.
peopleA-own [recently-greeted-people recently-greeted-people-time]
And then everytime that a personA has to greet someone your procedure could look like this:
to greet [personB-who]
if (not (and (member? personB-who recently-greeted-people)
(procedure-that-checks-ticks-less-than-5))
...ADD HERE OTHER LOGICAL CHECKS DEPENDING ON YOUR PROBLEM
)
[
fput personB-who recently-greeted-people
fput current-tick recently-greeted-people-time
]
end
Observe that for every personB greeted, the who and the id are added to different lists and then they must be removed at the same time to keep consistence.
You can read more about breeds in the NLogo dictionary.
Finally, following your suggestions, I ended up with this solution:
set potential-persons-b sort (targets-on (patch-set neighbors patch-here))
if (previous-person-b-greeted != [])
[
foreach previous-victimized-target
[ set potential-persons-b remove ? potential-persons-b]
set potential-persons-b turtle-set potential-persons-b
]
Here a more general solution using to-report:
to-report subsetting-agents [agent-set1 agent-set2]
set agent-set1 sort agent-set1
set agent-set2 sort agent-set2
foreach agent-set2
[ set agent-set1 remove ? agent-set1]
set agent-set1 turtle-set agent-set1
report agent-set1
end
I apologise upfront if this is a stupid question.
When one calls nw:weighted-path-to a list of links is returned describing the shortest path between origin and destination turtles.
Similarly, calling nw:turtles-on-weighted-path-to returns a list of the turtles on the shortest path between origin and destination.
It is my understanding that if there are 2 equally weighted paths between origin and destination both functions returns one of these paths at random. This happens independently and as such one set of links can be produced for the shortest path, but another set of turtles. This can be replicated using the following code:
extensions [nw]
links-own [ weight ]
to go
clear-all
create-turtles 4
ask turtle 0 [ create-link-with turtle 1 [ set weight 2 ] ]
ask turtle 0 [ create-link-with turtle 2 [ set weight 2 ] ]
ask turtle 1 [ create-link-with turtle 3 [ set weight 2] ]
ask turtle 2 [ create-link-with turtle 3 [ set weight 2] ]
ask turtle 0
[
let pathLinks nw:weighted-path-to turtle 3 "weight"
let pathNodes nw:turtles-on-weighted-path-to turtle 3 "weight"
let pathUtility nw:weighted-distance-to turtle 3 "weight"
show pathLinks
show pathNodes
show pathUtility
]
end
Which will happily produce:
(turtle 0): [(link 0 2) (link 2 3)]
(turtle 0): [(turtle 0) (turtle 1) (turtle 3)]
(turtle 0): 4
Obviously, this is not an error but it has unfortunately tripped me up.
My question is - what is the most sensible way to link these two procedures to produce lists of links and turtles that make up a single randomly selected shortest path?
I am assuming it would be best to return the links with nw:weighted-path-to, then ask the links to return both-ends and do some sort of unique operation to produce a set of turtles on that path, if that is the case I'm not sure how to preserve the order of turtles. Does this make sense? Is that how you would do it?
As ever, thanks for reading.
Edit: this also applies to path-to and turtles-on-path-to in a topological network with multiple equal length paths.
Good question! You can generate either list from the other, but I think turtle-path to link-path is easier:
;; Construct the turtle path, putting the current turtle on the front:
let turtle-path fput self nw:turtles-on-weight-path-to turtle 3 "weight"
;; Iterate through pairs of turtles, getting the link connecting them
let link-path (map [[link-with ?2] of ?1] but-last turtle-path but-first turtle-path)
Edit:
Nicolas is absolutely right about "link-path to turtle-path". However, his comment made me realize you could use the almighty reduce and the ever-useful other-end to do it!
reduce [ lput [[other-end] of ?2] of (last ?1) ?1 ] fput (list self) nw:weighted-path-to turtle 3 "weight"
Edit2: The "link-path to turtle-path" code is pretty opaque. Here's an attempt to clarify it:
to-report add-link-to-turtle-path [ turtle-path next-link ]
let last-turtle last turtle-path
report lput [[other-end] of next-link] of last-turtle
end
;; turtle-procedure - Assumes the current turtle is the starting point of the path
to-report link-path-to-turtle-path [ link-path ]
let start-of-path (list self)
report reduce add-link-to-turtle-path fput start-of-path link-path
end