How to select an object shared with my neighbours - netlogo

I am working on a model where turtles can exchange objects, like a virus, disease or just a ball.
After selected randomly one turtle, this turtle created an object as follows
create-object 1[ hide-turtle set new_object self set chosen? false]
set selected one-of breed1
ask selected [
set attribute random-float 1
set my-list fput attribute my-list
]
to put into a list shared between the turtle and its neighbourhood.
Now, what I would like is to consider another option for the same turtle, i.e. to choose one of the (old) items collected in its list based on the items' attribute: the higher the value, the more likely it is to be chosen.
ask one-of breed1
let selected-objects objects with [not chosen?]
let choice rnd:weighted-one-of selected-objects [attribute]
ask choice [set chosen? true]
set my-list fput choice my-list
]
where
globals [
chosen?
new_object ; in alternative to (list attribute in my-list)
]
breed[breed1 breed_1]
breed[objects object]
breed1-own [
my-list
my-list?
attribute
choice
]
My doubts are:
how can I keep this object in 'memory'/in list with its attribute?
I would need to keep in memory as the turtles (breed1) can exchange/spread the object/virus through time, but potentially this object can change its attribute's value.
would it be better to add to the list the object and/or its attribute?
if I wanted to change its value, after selected, how could I do?
Thank you for your time

OK, so you asked
(1) how can I keep this object in 'memory'/in list with its attribute?
I would need to keep in memory as the turtles (breed1) can
exchange/spread the object/virus through time, but potentially this
object can change its attribute's value.
Once you create them, the objects will persist until you kill them. This means that the attribute that each object owns will also persist without any effort on your part.
Looking at your code, you could keep track of which object is chosen by setting the global variable "new_object" to be the who number of the object you chose. .
The object with the given who number can have its attribute changed by anyone, anytime and all the other agents will be able to see that new value.
You also ask:
(2) would it be better to add to the list the object and/or its
attribute?
I would answer, don't put either the object or the attribute of the object on the my-list. Put the who number on the my-list. From the who number you can find the object with that who number, and from the object you can find the attribute.
OK, so if you do that, can you sort the list by attribute? Yes, you can do that with some clever code. The key line is the one sorting the list by the attribute of the objects which have their who numbers in the list my-list.
let temp2-list sort-on [ attribute ] objects with [ member? who [my-list] of myself ]
I think the answer to your third question should be clear now.
if I wanted to change its value, after selected, how could I do?
Here's working code that should help explain this answer. Setup generates one
agent and 6 objects and makes up a random my-list and a corresponding list of
attributes. Go generates sorted lists of objects and attributes. The object
in the list with the highest attribute is identified.
Note that objects-own [attribute]. You didn't mention that.
The example code is heavily documented in-line.
globals [
chosen_object_who
acting_breed1_who
]
breed[breed1 breed_1]
breed[objects object]
objects-own
[ attribute ]
breed1-own [
my-list ;; list of who numbers of objects, initialize to [] or it may fail
attr-list ;; list of attributes of the my-list objects, in the same order
attribute-of-chosen-object
who-of-chosen-object
my-list? ;; unknown
]
to setup
clear-all
print "creating 5 objects"
create-objects 5 [ set attribute random 100
print (word "created object " who " with attribute " attribute )
]
create-breed1 1 [
set my-list []
set attr-list []
set my-list? false
set attribute-of-chosen-object -1
set who-of-chosen-object -1
]
ask one-of breed1 [
set acting_breed1_who who
;; add six random object to my-list then remove duplicates
repeat 6 [
set my-list fput [who] of one-of objects my-list
]
set my-list remove-duplicates my-list
;; create the list of corresponding attributes
set attr-list map [i -> [attribute] of object i ] my-list
print (word "at end of setup, here's the my-list: " my-list )
print (word "here's the corresponding attr-list : " attr-list )
print ""
]
reset-ticks
end
to go
ask one-of breed1 [ ;; there is only one for this example
;; here's the magic command line
let temp2-list sort-on [ attribute ] objects with [ member? who [my-list] of myself ]
;; print (word "temp2-list: " temp2-list)
;; yields a list like [(object 3) (object 1) (object 4) (object 2) (object 0)]
;; it looks like an agent set but it's actually a list of objects in my-list,
;; but sorted into order by ascending attributes.
;; generate the new my-list, in the new order
set my-list map [i -> [who] of i ] temp2-list
set attr-list map [i -> [attribute] of i ] temp2-list
print "=========== after sort ====================="
print (word "sorted my-list now is " my-list)
print (word "matching attr-list is " attr-list )
print ""
;; You can select the best choice as the last item in the list, giving you the
;; who number of the object which has the highest attribute value
let best-choice 999
if-else length my-list > 0
[ set best-choice last my-list ]
[ error " my-list is empty! "]
;; saved as a global
set chosen_object_who best-choice
;; also save variables in the breed1 we are looking at now
set attribute-of-chosen-object last attr-list
set who-of-chosen-object last my-list
print (word "Assuming we want the object with the highest attribute")
print ""
print (word " The best choice object-who is " best-choice )
print (word " the attribute of that choice is " last attr-list )
print " "
print " all set to do something with the chosen object "
print " the choice is known both locally and globally "
inspect self
]
tick
end

Related

How to add items to neighbours' lists of an agentset that hatches another one?

I currently have one agentset(breed1) hatching another agentset(breed2). What I would like is to edit the breed2 (attribute1 and attribute2), then add the edited item (called item in the hatch) to the lists of the breed1's neighbours.
EDITED:
Working on the code after Wade Schuette's answer, I wrote the following
breed [people person]
breed [items item_1]
people-own
[
my-list
attribute1
attribute2
]
items-own
[
selected
attribute1
attribute2
]
to setup
clear-all
;; make turtles to test
create-people 1 [ set my-list [1 2 3 ] ]
create-people 1 [ set my-list [ ] ]
create-people 1 [ set my-list [22 33 ] ]
create-people 1 [ set my-list ["a" "b" "c"] ]
create-people 1 [ set my-list [3 4 5 ] ]
;; make a network
ask people [ create-links-with other people ]
reset-ticks
end
to go
let picked nobody
let neighbours nobody
ask one-of people
[
set attribute1 random-float 1
set attribute2 random-float 1
hatch-items 1 [
set selected picked
let this-item self
ask myself[
print (word "turtle " self " has item " this-item " with attribute1 " attribute1 "and attribute2 " attribute2)
set my-list lput this-item my-list
show my-list
]
ask link-neighbors [ print (word "Person " who " has this my-list " my-list)
set attribute1 (attribute1 + random-float 1)
set attribute2 (attribute2 + 3)
set my-list lput this-item my-list
print (word "added item " this-item " with attribute1 " attribute1 " with attribute2 " attribute2)
show my-list
]
]
]
tick
end
As you can see, my difficulties are in considering the turtle's neighbours and in updating the information (attribute1 and 2) of the item that I want to add in their lists.
You only need to make two changes to get your code to work.
Move the close-bracket ( ] ) for the hatch statements up BEFORE you try to ask for link-neighbors. Right now, you're asking for link-neighbors for the hatched agent, not the one that called it, so it finds none and fails silently.
If you do that, you get an error about this-item being undefined. That's because you declared it inside hatch code, so it goes away when hatch code closes. To fix that, declare this-item just before you call the hatch code ( let this-item "") works fine, but be sure to use LET not SET.
Then later, when updating linked neighbors, you only need to SET it, because you've already declared it.
I think with those changes it will work. Here's what I got to work. I put it many debugging xprint statements and set global verbose? to true to activate them, as I mentioned earlier. Doing all these print statements revealed the problem where link-neighbors suddenly appeared to disappear -- that's how I located the bug.
Set global verbose? to false in setup to deactivate them and get clean output.
globals [
verbose? ;; to turn on debugging statements
]
breed [people person]
breed [items item_1]
people-own
[
my-list
attribute1
attribute2
]
items-own
[
selected
attribute1
attribute2
]
to setup
clear-all
set verbose? true ;; true means printa lot of stuff
;; make turtles to test
create-people 1 [ set my-list [1 2 3 ] ]
create-people 1 [ set my-list [ ] ]
create-people 1 [ set my-list [22 33 ] ]
create-people 1 [ set my-list ["a" "b" "c"] ]
create-people 1 [ set my-list [3 4 5 ] ]
;; make a network
ask people [ create-links-with other people ]
;; ADDED next 2 lines
xprint (word "Created this many links in setup: " count links)
ask person 0 [
let fastcount count link-neighbors
xprint ( word "In setup, person " who " has this many links " fastcount )
]
reset-ticks
end
to go
let picked nobody
let neighbours nobody
ask one-of people with [ who = 0 ]
[
let fastcount count link-neighbors
xprint ( word "Entering ask-person, person " who " has this many links " fastcount )
set attribute1 random-float 1
set attribute2 random-float 1
xprint ( word "Before hatch-items, we have this...")
xprint (word "turtle " self " has no item hatched, "
" with attribute1 " precision attribute1 2 " and attribute2 " precision attribute2 2)
let this-item 0 ;; this was down inside hatch-items, so it evaporated when
;; finishing hatch-items, causing a problem
;; DECLARE it up here, then SET it inside hatch-items
hatch-items 1 [
set selected picked
set this-item self ;; this was down here inside hatch-items, move it up 4 lines
xprint ( word "confirming this-item value is: " this-item )
ask myself[
xprint ( word "inside hatch-items , inside ask-myself, we have this...")
xprint (word "turtle " self " has item " this-item
" with attribute1 " precision attribute1 2 " and attribute2 " precision attribute2 2)
set my-list lput this-item my-list
xprint ( word "hatched item now has my-list = " my-list )
] ;; end of ask myself
];;; <====== you want to close context of hatch-items up here, not down below
;;; so that ask link-neighbors will work
;; ADDED THIS NEXT LINES FOR DEBUGGING
xprint "we are done with ask myself, but still inside hatch-items"
set fastcount count link-neighbors
xprint ( word "After ask myself, but still inside hatch-items, person " who " has this many links " fastcount )
xprint ( " the code posted in the revised question failed here")
xprint ( " PERSON should be person 0 , link count should be 4 ")
xprint ( " SO ASK LINK-NEIGHBORS WIll fail !!!")
xprint " asking link-neighbors to update their lists now"
ask link-neighbors [ print (word "Person " who " has this my-list " my-list)
set attribute1 (attribute1 + random-float 1)
set attribute2 (attribute2 + 3)
set my-list lput this-item my-list
xprint (word "added item " this-item " with attribute1 " attribute1 " with attribute2 " attribute2)
show my-list
]
;;] ;; closes context of hatch-items, try closing hatch-items before asking link-neighbors
]
tick
end
to xprint [ stuff ]
if verbose? [ print stuff ]
end
Minor typo: one of your methods uses in-link-neighbors and one uses link-neighbors. Unless you want to exclude outbound links, I think you want link-neighbors.
Basically, one design question you are asking is whether it's better to find the set of the caller's link-neighbors before hatching and save that in an attribute, or to find them locally at the time of hatching and forget the list after hatching. I haven't tried your code, but I think both methods would work. If the set of links is static, you could find it once, store it, and not bother finding it again every time you hatch a new agent, and save some time. If the set of links is dynamic, you need to look it up every time anyway, so there is no point in saving it in an attribute.
You ask how to validate the code. I have no idea what either of your suggestions mean so I'll answer the general case. These are probably steps that you could do, and should do, before posting here, to fix all that you can fix by yourself.
Rule #1: Start simple, and get that much working before adding complexity.
Your code already violates Rule #1. You set two attributes when you could be testing with only one. What if the second attribute code causes an error that confuses your checking that the overall logic is working. For that matter, start testing with zero attributes. Comment out that code and add it back in gradually, checking again at each step.
Rule #2: Take small steps.
Confirm that the code works with only one agent before adding more agents. Make one pass of the "go" step and stop to test. Get that much perfect before moving on to a second step. Etc.
We can all dream of the day when NetLogo has a real debugger that lets you step through the code one statement at a time, or set break-points. But it doesn't. By the time the go step is over and a "stop" takes effect, you've lost context. Local variables have evaporated and can't be checked. The "stack" of nested calls is lost.
The only way I know of to see the dynamic details in context is to either set new global variables, which is messy, or make heavy use of embedded "print" statements.
You could also insert an error statement to cause a run-time error, examine the calling stack, and have a chance to take a breath and look at the output at that point.
error " here is the calling stack, halting execution entirely here."
Or, you can use a user-message statement to cause the code to pause to let you know that something has changed, or that a condition that never should occur (!) has now occurred. This gives you the nice options of "halt" or continuing to run as if nothing happened.
if x > 5 [ user-message " Alert -- X is over 5!! " ]
Other reviewers, chime in here and share other ways to do this!
The most useful print statements I've found label several variables of interest and identify where they are executed so you can tell them apart in the output. Example for looking at 3 variables x,y, and z:
print ( word "In step 3, x = " x " y = " y " z = " z )"
It would be great if there was a way to toggle visibility of these statements in the editor, but there isn't. You can at least toggle whether the statement runs or is skipped by adding a global variable, say "verbose?" and changing the print statements to take advantage of it. ( see below )
Then you can turn on or turn off printing all of these statements at once, as opposed to commenting them out, or worse, deleting them. In general, don't delete them, because someday you will need to modify and re-validate the code, and you'll need these back again to confirm that the modifications are doing what you want them to do and didn't break something new. Good "print" statements are worth their weight in gold and worth effort to get in place.
Here's a nice way to have selective printing. Declare a new command called "xprint" that only prints when the global variable "verbose?" is true. You can set it once in setup, or modify in go mid-stream, or set verbose? true or false in the Command Center you step through code.
Then you can use "xprint" instead of "print" where you want to be able to toggle printing or no printing.
xprint ( word "In step 3, x = " x " y = " y " z = " z )"
That really lowers the cost of having lots of print statements in your code, so it really simplifies the process of verifying code and re-verifying it later.
;; This shows how to use a global variable to turn on or off print statements,
;; which you might want to use while developing and testing code
globals [
verbose? ;; true means print lots of things, false means don't print them
]
to setup
clear-all
set verbose? true ;; or false, whatever. You can also use the Command Center
;; to set this true or false in the middle of a run
reset-ticks
end
to go
let x random 10 ;; just for illustrating how this works
xprint (word "At tick " ticks " x = " x )
tick
end
to xprint [ stuff ]
if verbose? [ print stuff ]
end
You said in a comment to the first answer:
The code works, but I have not been able to print all the neighbours
of the selected turtle and see if the item was added or not to their
lists. .... However, my difficulties are in
considering and defining the neighbours of the turtle (myself).
Can you explain what difficulties you are having? Can we pick an easier example to work with? Is the problem you are having with what agent is meant by the word "myself" and "self" depending on how deeply you are nested in ask-whoever calls?
Here's some easier code to start from. Can you create the problem with this code?
By the way, if you are an ask loop within another ask loop, the keyword "myself" will be defined and you can use
print (word "At point 3, self = " self ", and myself = " myself)
to see who is who. I don't know how to test whether "myself" exists, since if it doesn't this throws an error -- testing = nobody doesn't work and is-agent? doesn't work if myself doesn't exist. Anyone? How can you tell if myself exists?
Anyway it doesn't matter. Here's a workaround. Just wait until after the hatch section is completed when you are back in the first agent's context, and you can use
ask link-neighbors [ print (word "turtle " who " has this my-list " my-list) ]
and it should work!
turtles-own
[
my-list
]
to setup
clear-all
;; make turtles to test
create-turtles 1 [ set my-list [1 2 3 ] ]
create-turtles 1 [ set my-list [ ] ]
create-turtles 1 [ set my-list [22 33 ] ]
create-turtles 1 [ set my-list ["a" "b" "c"] ]
create-turtles 1 [ set my-list [3 4 5 ] ]
;; make a network
ask turtles [ create-links-with other turtles ]
reset-ticks
end
to go
ask one-of turtles
[
ask link-neighbors [ print (word "turtle " who " has this my-list " my-list) ]
]
tick
end

How to give a score when an element is pulled out from a list?

I would like to implement a part of code where agents can get a score when they pick an element from a list generated from a specific turtle.
I set
breed [playersA playerA]
breed [playersB playerB]
breed [balls ball]
playersA-own[
my-list
new_ball
score
]
playersB-own[
my-list
new_ball
score
]
to setup
clear-all
create-playersA 10
ask playerA 0 [ create-links-with other playersA ]
ask playerA 2 [ create-link-with playerA 1 ]
create-playersB 10
ask playerB 0 [ create-links-with other playersB ]
ask playerB 2 [ create-link-with playerA 1 ]
ask playersA[
set my-list []
set score 0
]
ask playersB[
set my-list []
set score 0
]
end
to go
let selected nobody
let team-player nobody
set selected one-of turtles with [breed=playersA or breed=playersB]
ifelse [breed = playersA] of selected[
ask selected [
set size [count link-neighbors] of self
show size
]
create-balls 1[
hide-turtle
]
]
[ ask selected [
set size [count link-neighbors] of self
show size
]
create-balls 1[
hide-turtle
]
]
set team-player link-neighbors with [breed = playersA]
ask team_player [
set my-list lput my-ball my-list
]
end
The above code should select on random turtle and add a new ball to its neighbours list. What I would need is probably a counter that can compute how many balls were shared between players.
Could you please help me to figure out with it?
Thanks
The code you posted has many problems that prevent it from passing error-checking in the editor. Some of these produce surprising error messages that don't even make sense, and they happen because the logic mixes contexts -- that is, some commands make sense for the "observer" level, some require being in a "turtle" context, etc.
I think you are trying to do too much at once, and trying to add a counter to code that already does not work. First you have to fix the code you have and then you can see where to add a counter.
You absolutely must understand how the unique agent id number "who" works. Each turtle has a unique who number assigned, starting with zero. It doesn't matter whether the breed of turtle is playerA or playerB or a ball, it will have a unique number. Once you create your first 10 turtles, of the PlayerA breed, they will have who numbers 0 through 9. Then, when you create the next 10 turtles, of PlayerB breed, they will get assigned who numbers of 10 through 19. If you then create a ball, say, it will have a who number of 20.
So there will never be a PlayerB with a who number of 0 or 1 or 2. Those numbers will already be used by PlayerA. Your setup will crash with the error:
playera 0 is not a PLAYERB error while observer running PLAYERB
called by Command Center
Even with just PlayerA, it is not clear what kind of network you want to build in the setup code. Why would everyone link to player 0, but then also add a single link between player 1 and player 2? Since players only "see" their linked team-mates, only player zero will see everyone else. Other players will have only one or two link-neighbors, so they will never update everyone else's my-lists.
create-playersA 10
ask playerA 0 [ create-links-with other playersA ]
ask playerA 2 [ create-link-with playerA 1 ]
Anyway, I would suggest that you get this much working correctly before trying to add counting.
I don't think you can do that by just looking at the code. You need to get rid of as much complexity as you can, and then use shapes, colors, and numerous print statements to see whether each command is doing what you think it should do. Complex working code almost always evolves from simple working code.
So get rid of PlayersB entirely ( comment out the code ), only create 5 players A, and change the colors and shapes as you process each step to confirm that it is working. The editor lets you use ctrl-; to comment out entire blocks of code, or un-comment them at once, so comment out everything you possibly can while you are getting one step to work, then uncomment the next section, get that to work, etc.
When you finally get everything working, you can comment out all your print statements that you used in development.
Anyway, I refactored your code, added many comment, and added many print statements, and finally got it to run. If you run just setup and look at the view, you will see what I mean about the network. ( I shut off wrapping in the view so the network looks right.)
Here's my revision of your code. It prints out what is in each player's my-list after each step, so you can see at a glance if it is doing what you want, or not. ( It's not.)
I added the who numbers as a label to each player in the view so you can see what I mean.
It produces helpful output like:
let's confirm that the lists have been updated. Here's the my-lists
for playersA [[5 5 5 5 10] [0 0 0 0 0] [0 8 8] [0 0] [0 9]]
Get the setup step to work correctly and generate the network you want before you even try to fix the go section.
breed [playersA playerA]
breed [playersB playerB]
breed [balls ball]
playersA-own[
my-list
new_ball
score
]
playersB-own[
my-list
new_ball
score
]
to setup
clear-all
;; for debugging, only create 3 players and inspect the results to confirm it's working as you intended
;; use labels to see player numbers in the view
create-playersA 5 [ set size 1 set color blue set shape "square" setxy random-xcor random-ycor set label who]
ask playerA 0 [ create-links-with other playersA [set color blue]]
ask playerA 2 [ create-link-with playerA 1 [set color red]]
create-playersB 5 [ set size 2 set color yellow set shape "person" setxy random-xcor random-ycor set label who]
; comment out this code until create-playersA is working properly
; ask playerB 0 [ create-links-with other playersB ]
; ask playerB 2 [ create-link-with playerA 1 ] ;; copy-and-paste error? link with playerB intended?
ask playersA[
set my-list []
set score 0
]
ask playersB[
set my-list []
set score 0
]
reset-ticks
end
to go
let selected nobody
let team-players nobody
let hot-ball nobody
set selected one-of turtles with [
breed = playersA
;; or breed = playersB ;; always select one of playersA for debugging this code
]
print ( word "At point 1, we selected turtle " [who] of selected " with breed " [breed] of selected)
;; we're still in the observer context here
ifelse [breed = playersA] of selected [ ;; by mentioning breed, we shift into a turtle context silently
print ( word " entering the TRUE part of the if-else statement " )
ask selected [
set size [count link-neighbors] of self
print ( word "at point 2 we set selected player's size to " size )
]
create-balls 1 [
set shape "circle" set size 3 set color blue set label who
set hot-ball who
; hide-turtle ;; for debugging show it so you can click on it and inspect it
print ( word "at point 3 we set created a blue hot-ball with who= " hot-ball )
]
;; it seems you want to update the selected turtle's my-ball variable here with a reference to the ball just created??
print " at point 4 we should set selected agent's my-ball to the ball we just made..."
ask selected [
set new_ball hot-ball
]
print (word " Confirming that selected player got the hot-ball " [new_ball] of selected )
;; ask ball hot-ball [ set hidden? true ]
;; this set of code seems to apply only when selected turtle is one of playersA, so it was moved INSIDE that ask-selected code
;; and put inside another ask selected [ ] context
ask selected [
set team-players link-neighbors with [breed = playersA]
print (word "At point 5, For selected player " who ", here is the team-players agent set :" )
print (sort team-players) ;; using "sort" here just to convert an agent set to a list for display
]
print " ------------- about to ask team-players to update their my-lists and change to triangles ---"
ask team-players [
set shape "triangle" set size 3 ;; to see at a glance that everyone was processed
set my-list lput new_ball my-list
print "... updated one my-list"
]
print " let's confirm that the lists have been updated. Here's the my-lists for playersA "
print map [ i -> [my-list] of i ] sort playersA ;; using "sort" to convert agent-set to a list
print (word "At the end of the go step, we have this many balls: " count balls)
]
;; else we should have breed != playersA
[
error " we should only be looking at one of playersA here for testing" ;; for debugging
]
;; tick
end

How to plot hatch-breed created by two different breeds

I am having some troubles to plot objects created using hatch.
I would like to plot objects created by engineersA and engineersB, separately.
After JenB’s answer, the code that I am using for this purpose is
sk one-of turtles with [breed = engineersA or breed = engineersB]
[ if empty? my-list
[ set size random-float 1
]
hatch-objects random 10
[ hide-turtle
ask myself
[ set my-list fput self my-list
]
]
]
What I tried to do is
ask engineersA [plotxy ticks objects]
same for engineersB.
Unfortunately, because of objects as a breed, it does not work.
I hope you can help me.
There are problems with context in your hatch-objects code, particularly with what values "self" and "myself" take on. The code as written will never put any objects on the my-lists. Explaining it is difficult so I wrote code (that runs) with a verbose? variable in setup. If you set verbose? to true, the print commands will print out what's going on in each step of the code. ( if you set it to false, the print commands won't print anything.)
At the end of the code are the commands I used to get a plot of the counts of objects created by each breed of Engineers. That is documented in the code right there, and it works correctly.
I decided to store text values of "A" or "B" in each object to show what breed created that object. It was a problem to store the breed in that variable and test for it, so I just used text, which worked.
I made the turtles large so that they were easy to click on an inspect.
This should be enough of an example for you to figure out how to compute and store the other things you want to do.
globals [
verbose? ;; set this true to print out debugging info
count-type-a ;; count of objects created by engineersA
count-type-b ;; count of objects created by engineersB
]
breed [engineersA engineerA]
engineersA-own [ my-list]
breed [engineersB engineerB]
engineersB-own [my-list]
breed [objects object]
objects-own[
creator-breed ;; set to either "A" or "B"
]
to setup
clear-all
set verbose? true ;; turns on and off debugging print statements
create-engineersA 3 [
setxy random-xcor random-ycor
set label who set size 3
set my-list []
]
create-engineersB 3 [
setxy random-xcor random-ycor
set label who set size 3
set my-list []
]
reset-ticks
end
to go
let breed-picked "none"
ask one-of turtles with [breed = engineersA or breed = engineersB]
[
;;set breed-picked breed ( produces a result that looks like a string but isn't)
if-else ( breed = engineersA) [
if verbose? [ print " this is breed engineersa "]
set breed-picked "A" ]
[ set breed-picked "B" ]
if verbose? [ print ( word "we are looking at turtle " who " now, which is breed " breed-picked) ]
if my-list = []
[
if verbose? [print "my-list is empty"]
; set size random-float 1
]
hatch-objects 3
[
set size 3 set color yellow set shape "circle"
set creator-breed breed-picked
if verbose? [
print ( word " in hatch-objects, myself = " myself)
print ( word " in hatch-objects, self = " self)
]
let object-tag self ;; so this will persist into ask myself
hide-turtle
ask myself
[
if verbose? [
print ( word " in ask myself, self = " self )
print ( word " in ask myself, object-tag = " object-tag)
print ( word " who of object-tag " [who] of object-tag )
]
set my-list fput object-tag my-list
if verbose? [ print ( word "hatched an object, my-list is now " my-list)]
]
]
]
if verbose? [ ask objects [ print creator-breed]]
set count-type-a count objects with[ creator-breed = "A" ]
set count-type-b count objects with[ creator-breed = "B" ]
print ( word "count of objects created by engineersA is now " count-type-a)
print ( word "count of objects created by engineersB is now " count-type-b)
;; The following code works. I'm sure there are better ways to do it.
;; The interface has a plot called "plot 1"
;; Within that plot object, two pens were created, called "type-a" and "type-b"
;; and the pens were given different colors.
;; The check box for "show legend" was checked.
;; Everything else was left at default values. The plot commands were left blank.
set-current-plot "plot 1"
set-current-plot-pen "type-a"
plot count-type-a
set-current-plot-pen "type-b"
plot count-type-b
end

Create a new item and add it to my neighbours's lists

I would like to ask how I can add an element created by one turtle to its own list and its neighbour's lists.
I created a local variable, neighbours, defined as turtle-set in-link-neighbors with [breed=breed1]. Then I asked neighbours to add the element created (new_elem), following an answer provided me by an user in this forum.
The code is:
to create_elements
create-elements 1[
set person one-of turtles with [breed = breed1 or breed = breed2]
ifelse [breed = breed1] of person
[
set attribute1 random-float 1
set attribute2 random-float 1
set function1 (1 + attribute1)
]
[
set attribute1 random-float 1
set attribute2 random-float 1
set function2 (1 - attribute1)
]
let neighbours (turtle-set self in-link-neighbors with [breed = breed1] of person)
ask neighbours
[set my-list fput new_elem my-list]
]
]
end
I know that there is an error in let neighbours (turtle-set self in-link-neighbors with [breed = breed1] of person)..., but also in putting an element in the list, as I think the new element is defined in the breed elements. In fact, the error message says that
elements breed does not own variable my-list
Would it be possible to specify the breed of the turtle-set? What I would need is consider only breed1 and breed2, not elements breed.
For example, since I am considering person as creator of the element, is it right to write
let neighbours (turtle-set person in-link-neighbors with [breed = breed1] of person)
ask neighbours
[set my-list fput new_elem my-list]
And if it would be correct, how can I add a new element as "New element" to the list, taking into account its attribute for further consideration.
For example: set my-list fput (list attribute1 attribute2) of elements my-list) returns me list of values like (0.134531 0.14141) (0.91844 0.42176) ... Any suggestions to have something nicer to see but with the same information? I will need to keep track of this values in the next steps.
I hope you can shed some light on what I am doing incorrectly.
Thanks
Val, here's some working code that creates a new element and updates everyone's my-list.
It's probably not exactly what you wanted but I hope it provides some help anyway.
You didn't include all the info on breeds and who owns what so I punted.
I broke up more complex commands into multiple shorter ones in order to debug what was going on and where it was breaking down. I added some print statements.
If you load this up, run setup, and hit "go" once, you can see agents in a network linked up with their "who" numbers besides them so you can easily inspect the ones you
want. Values of my-list are also printed out in the command section.
Two more iterations of the "go" step should verify that they are outputting what you wanted.
I didn't know whether you wanted new_elem to be just local to the create_elements section, of if you wanted it globally available, so I put comments in both places.
I hope this helps! There are more comments in the code itself. Note especially that you must initialize my-list as an empty list, or it will default to the number zero, and your fput statement will fail with a comment about expecting a list and finding zero.
globals [
;;new_elem ;; might be needed as a global ??
]
;; ///////////////////// note that there is no breed required called "people"
breed [ elements element]
breed [ breed1 lion ]
breed [ breed2 tiger ]
;; ///////////////////// i punted on which entity owned "function1 and function2
breed1-own [ attribute function1 function2 my-list]
breed2-own [ attribute function1 function2 my-list]
to setup
clear-all
;; make some turtles with breed = breed1 (say, red lions)
create-breed1 2 [ set size 2 set shape "circle" set color red
setxy random-xcor random-ycor
]
;; make some turtles with breed = breed2 (say, green tigers)
create-breed2 2 [ set size 2 set shape "circle" set color green
setxy random-xcor random-ycor
]
;; //////////////////////////////////////////////////////////////////////////
;; NOTE!!! If you don't initialize my-list to an empty LIST type,
;; fput will generate an error when you try to fput a new element onto it
;; this is ugly but fast:
ask breed1 [create-links-with other breed1
set my-list [] ]
ask breed1 [create-links-with breed2
set my-list [] ]
ask breed2 [create-links-with other breed2
set my-list [] ]
ask breed2 [create-links-with breed1
set my-list [] ]
ask turtles [set label who] ;; ///////////////////////// for debugging
;; set new_elem nobody ;; this could be a global so it can persist
;; outside create_element, in which case
;; initilize it here
reset-ticks
end
to go
create_elements
tick
end
to create_elements
;; declare the local variables, all agent-sets of some type
let new_elem nobody ;; declare this locally if we don't need to persist it
;; outside the create_elements context
;; and remove the declaration in [ globals ]
;; and initializtion in setup
let personx nobody
let xx-neighbors nobody
;; do just this creation here in order to see what's going on more easily
;; than combining multiple operations into a long complex command
create-elements 1 [ set new_elem self ]
type "new element is this agentset " show new_elem
set personx one-of turtles with [breed = breed1 or breed = breed2]
ifelse [breed = breed1] of personx
[ ;; if it is breed1
ask personx [
set attribute random-float 1
set function1 (1 + attribute)
]
]
[ ;; else, it must be breed2
ask personx [
set attribute random-float 1
set function2 (1 - attribute)
]
]
;;//////////////////////////////////////// for debugging
type "the personx we defined above is " print personx
ask personx [set xx-neighbors (turtle-set self in-link-neighbors )]
if-else xx-neighbors != nobody ;; If it has any members, which should
;; always be true since we added self to the set
[
ask xx-neighbors
[
set my-list fput new_elem my-list
;; ////////////////////////////////////for debugging
type "here's the resulting my-list: " show my-list
]
]
[ print "ERROR didn't find any neighbors or self" ]
end

subsetting agentsets transforming a list of agents into an agentset

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