I'm very new to netlogo and was working on "Follower" model.
In extending the model propositions there is a "what if two turtles are allowed to have the same leader?"
I was wondering if there is a way to count the number of followers in turtles
(something like
count follower
and then use it in a way like :
let candidate one-of (turtles-at xd yd) with [follower = nobody or count follower < 2]
which gives this error on runtime:
COUNT expected input to be an agentset but got the turtle (turtle xxxx) instead.
I solved the problem with a hack (adding a new variable f-num and then incrementing it when a new turtle is attached to the current turtle, and selecting candidates with the condition f-num < 2) but wanted to know if there is a better way for such a problem
The problem is that the original statement for setting follower is
ask candidate [set follower myself]
and myself is not an agentset, is an agent. This means that, unless that statement changes, follower is never going to be something countable: you can count how many agents are there in an agentset (which could also be an agentset of 1 or of 0), but you cannot count an agent.
The solution then has to be to change that statement, initialising follower as a different object - one that accommodates multiplicity (which means one on which you can perform an addition and one that you can measure).
Solution with agentset
As I said, agentsets can be counted. Actually, agentsets are the natural type of object that count operates on. Therefore, we could initialise follower as an agentset.
A way to do it is by using turtle-set:
...
ask candidate [set follower (turtle-set follower myself)]
...
In that case, for consistency I would also change the create-turtles population bit by doing:
...
set follower (turtle-set)
...
This way, follower will be an agentset for all turtles since the beginning (starting as an empty agentset instead than as nobody).
I would much prefer it for consistency, but pay attention that this means that all the conditions asking whether follower = nobody don't make sense anymore: an empty agentset is different from nobody!
In fact, if you just make the above change, then click on setup and then run count turtles with [follower = nobody] in the Command Center, you would get 0.
Running instead count turtles with [count follower = 0] you would get all the turtles.
So the conditions with nobody will have to be changed accordingly; and, in particular, the one that was the object of your question will become a tidy
...
let candidate one-of (turtles-at xd yd) with [count follower < 2]
...
So, to bring back a bit of tidiness, let me put these three changes in their in-code logical order:
; The initial declaration when you create turtles:
...
set follower (turtle-set)
...
; The condition where you test how many followers a turtle has:
...
let candidate one-of (turtles-at xd yd) with [count follower < 2]
...
; The action of adding a follower:
...
ask candidate [set follower (turtle-set follower myself)]
...
; Plus changing other instances where the original code says 'with [follower = nobody]'.
NOTE
As you saw from the description of turtle-set, it is a very flexible primitive: basically it turns anything into an (turtle) agentset.
The most common way to create agentsets on the go, however, is using with. The logic is that a subgroup of an agentset is still an agentset; given that with can only be used on agentsets, what it gives you back can only be an agentset.
In our case, however, using with would have not been that tidy/simple.
The follower variable could have been initialised as an agentset quite easily using with:
ask candidate [set follower turtles with [who = [who] of myself]]
However, this only command would have set follower each time as the agentset containing the only turtle with that specific who, thus not helping with the intention of incrementing the numerosity of the agentset.
This is when things would have started to become more convoluted than just using turtle-set.
Solution with list
Another type of object that can be counted are lists. As you can imagine, you don't count lists with count but you can do it with length.
In this case, we just initialise follower as a list, add agents as items to the list using lput or fput (depending on how one wants to use the list), count the length of the list when checking the condition.
Changes mirror the ones we made in the agentset solution:
; The initial declaration when you create turtles:
...
set follower (list) ; or
set follower []
...
; The condition where you test how many followers a turtle has:
...
let candidate one-of (turtles-at xd yd) with [length follower < 2]
...
; The action of adding a follower:
...
ask candidate [set follower (lput myself follower)]
...
; Plus changing other instances where the original code says 'with [follower = nobody]'.
Using a list will be useful if you want to keep track of the order of turtles following the leader. In fact, while lists are ordered objects, agentsets are unordered (literally agents in an agentset come/act in a random order everytime you call that agentset).
Related
Any tips on how to model agent behaviour in an environment where two sets of rules apply simultaneously.
Specifically, what I am looking to simulate is a situation where an Agent operates under a specific set of rules, such as an employee-employer relationship, but at the same time, operates on perhaps different "informal" rules, such as an employee-employee relationship. Effectively there are two network structures in place, but the agent operates in both structures.
Any example models out there that I could take a look at?
(This is a model design question, not programming, so it probably belongs on the NetLogo user group instead of here.)
My colleague and I wrote a book on modeling decisions that are tradeoffs between competing objectives, in ABMs. It's focus is on ecology but the concepts could be useful for you.
The basic idea is to come up with an objective function that includes both "sets of rules" as you call them. Perhaps something like maximizing your relations with fellow employees without getting fired by the employer. Then build very simple models of how decisions affect the mechanisms that drive co-worker relations, probability of getting fired, etc. It's not simple, but it's very powerful and flexible. You won't find a simple approach that's very general.
The fun part is trying different variations and comparing how they work.
https://press.princeton.edu/books/paperback/9780691195285/modeling-populations-of-adaptive-individuals
Maybe I’m under-thinking this, but..I would encode both (all) sets of rules, and have the agent execute those rules as appropriate.
So, how to choose and execute rules?
Per social interaction:
Execute one behavior randomly based on which relationships are present
Choose one or more behaviors, as #1 and execute all of them in a specific order
As above, but execute behaviors in random order
For all possible behaviors, assign a probability based on whatever factors (number of role-members present, utility, consequence, etc l) Choose and execute one behavior randomly based on that probability (roulettes-wheel selection)
Choose more than one… execute in fixed or random order
Proportionate to the value of a “social-competence” property, Select a number of possible behaviors as #4. Then randomly select one of those to execute.
Here’s a code-segment example of #6
;; list of possible reactions
;; these are variables or reporters that report
;; an anonymous command that executes the behavior
Let action-list (list
boss-action
employee-action
coworker-action
peer-action
)
;; measure social situation
;; list of values from reporters
;; these are reporters that return a value
;; based on, for example, how many of that type of
;; relationship are present.
Let choice-list ( list
( probability-of-doing-boss-behavior )
( probability-of-employee-behavior )
( probability-of-coworker-behavior )
( probability-of-peers-behavior )
)
;; think about situation, choose possible actions,
;; as many times as social-competence allows.
;; roulette-wheel should return the index of the selected action
Let reaction-list (n-values social-competence
[ -> roulette-wheel choice-list ] )
;; choose an action from those options
Let action-index one-of reaction-list
;; execute that action
Run item action-index action-list
The same result as a single combined objective function might be a physics type model where the result of any single set of rules is a vector of some strength pushing ("nudging"?) the agent in some direction. Then you could have as many sets of rules as you want, each contributing it's own vector of force, and the final result would be a resultant combined net force and subsequent Newtonian F=m*a or rearranging acceleration = ( vector sum of forces )/mass.
I'm trying to imagine how I respond when the expectations of different groups I belong to clash, and whether a linear sum vector model describes it. I recall in college when I couldn't resolve Catholic support for the Vietnam War and "Kill for Christ" was a tongue-in-cheek slogan. I think in that case the "forces" didn't cancel out -- they resulted in ABANDONING membership in one of the groups to reduce cognitive dissonance. So, not a linear sum of zero in that case.
Another unstable human approach might be to keep going back and forth when two forces attempting to dominate behavior conflict -- first going with one a few steps then feeling guilty and going the other way a few steps. So which one dominates at any given step might depend on one's recent path and history and which one you "owed" something to. Or imagine being married to two people and trying to keep both of them happy. Maybe you partition space and Monday-Tuesday-Wednesday you keep one happy and Thursday-Friday-Saturday you keep the other happy and Sunday you go fishing.
I would like to track the path of a wallet stolen by a thief. The model should create a network of thieves, each of them with their own bags where they put the stolen objects (I am setting this objects - wallets - as self).
Let suppose that thief1 has in his own bag [wallet1 wallet2 wallet4] and his neighbour has [wallet1 wallet3] as wallet1 was added in his own bag.
If the neighbour with bag [wallet1 wallet3] wants to pick randomly one of the two items to return to the police, for example wallet1 (and this can be done using [let picked_wallet one-of turtle-set my-bag]), how can I add a 'tag' or something that can tell me that the first thief to stole that wallet was the thief1?
globals [this-wallet]
breed[thieves thief]
thieves-own [my-bag wallet-id]
to setup
clear-all
create-thieves 5
ask thieves [ set my-bag [] create-links-to other thieves ]
ask one-of thieves [ set this-wallet self set my-bag fput self my-bag ask link-neighbors [set my-bag fput this-wallet my-bag print "Neighbours " show my-bag ]]
ask one-of thieves [ set this-wallet self set my-bag fput self my-bag ask link-neighbors [set my-bag fput this-wallet my-bag print "Neighbours " show my-bag ]]
ask thieves [show link-neighbors show my-bag]
reset-ticks
end
In response to your comment on my last answer, here's a new answer.
Well, a virus problem is different from a wallet problem and needs different data structures.
Still, viral transmission can be modeled as a series of transactions, so the idea of using a global master list of transactions to keep track of what has gone on is still a workable approach.
You COULD also keep a list on each agent of who they got a virus from and when, but it would be redundant with a single master list -- you can simply filter the master list of transactions by agent to see exactly the same information as what you are trying to keep in many lists at the agent level. I'm not sure why you do not like that approach.
Keeping one list is much cleaner than keeping many lists. Any question you could ask agents-with-lists you could also answer by searching the global list.
It would make sense to have a little redundancy for viewing what is going on and for simplifying the ASK command you will use to spread the virus -- so you could store at the agent level whether the agent is currently-infected? and color-code infected agents to tell them apart from never-infected agents and fully-recovered? agents and dead? agents.
Even that could be reduced to a single status variable with legitimate values of "healthy" "infected" and "recovered" and a single is-immune-now? flag. That would be enough to figure out who is contagious, who is infected, who could possibly become infected, who has recovered, who has died, etc.
Of course, if you are playing epidemiologist and trying to track down where the infection came from ( "patient zero") you COULD add a variable showing for each person WHO they got infected BY and when and write some long recursive code to trace back step by step where that linked-list started. OR, you could just get the same answer in a simple single filtering pass of the master list of who infected whom and when.
Maybe doing this the easy way is "cheating" and you want to play doctor instead of God and you want to show how it could possibly be tracked back one step at a time? Or you want to show how an epidemiologist might go to a lot of effort to build a "tree" diagram showing where the infection started and how it spread down different branches?
That's an INTERESTING problem but it is not the question you asked.
If you want to find the ultimate-source-turtle for an item in a list, you need to modify your data-structure. One way ( the hard way ) to do that would be to store more information in each turtle's list -- so at the time the virus is added to the list you ALSO add a timestamp and a source-turtle. Possibly you could store this information as triplets in a list such as [ source-agent-id tick-acquired virus-type ] and so each agent would have a list of such triplet-lists. That could work. That's one way to do it.
That would require that you add some complexity to the process that puts the virus on their list. It would have to build a list of the 3 items and put that list onto the target my-list of any agent it infected. ( In your case the virus seems to be 100% contagious and anyone with it gives it to everyone else! )
So your ASK-TURTLES logic would be a little bit more complicated. You could manage the complexity by having little to-report routines that packed the triplet-list or unpacked it.
OR, with fewer lists to manage, you could have your ASK-TURTLES logic store a series of transactions, that you could code as 4-item lists: [ source-id target-id virus-type tick-infected ] and store that in a master list-of-lists in a global variable. You still might want to set the target-turtle's variables of "status" and "immune-now?" at the time you are infecting the next agent to simplify identifying which turtles are contagious and which turtles are immune to simplify the next go step where you would ask turtles who are contagious to infect turtles who are not immune and are within a given radius, etc.
You asked
how can I add a 'tag' or something that can tell me that the first
thief to stole that wallet was the thief1?
I'm not clear about what operation corresponds to "stealing a wallet". Is the agent doing the stealing the one who puts the wallet on someone's list? Or the one whose list it gets put on?
In your example you have two different people with "wallet1" on their list, so I'm also not clear about who "has" the wallet. How can one wallet be two places at once? In fact it's more than two places, when it's put on one thieves list, it's put on every thieve's list. What is that operation supposed to represent? Is that "stealing"?
Are you trying to figure out which of the many copies of wallet1 got put on any agent's list first in time? Of course that's a little hard because agent sets are always processed in a random order, so the code you show gives no clue to who got it first.
What I'm suggesting is that the data-structure you have doesn't seem to do a good job of representing real-world operations, and if this doesn't confuse the current question of who got the wallet put on their list first, which is what I think you're asking, it will surely confuse other questions down the road. The operation you show for updating the lists makes it impossible to determine which thief got it first.
It certainly confuses me. I think your coding would be much easier if there was only ever one copy of wallet1 in existence, and it was only on one agent's list at a time, and the agent's list was only one entry long, and you had a "steal-wallet" procedure that removed a wallet from one agent's list and put it on exactly one different agent's list. Then it would be clear what time that happened.
Or are these lists supposed to represent knowledge one agent has about the existence of the wallet? Or do they represent all wallets that ever existed owned by anyone over all historical time, in which case the "same" wallet might appear many different times, each time representing a different owner, and even the same wallet and the same owner might be stolen and stolen back multiple times so even that pair of facts (wallet-id and new-owner) would not be unique.
For one thing, if everyone is going to end up with identical lists, then find some place to put the list once and be done with it -- don't give everyone a copy when one copy will do. The list doesn't even need to be owned by anyone -- it can simply be a global variable. That would simplify a lot. Then you only have one wallet, and each time it changes owner you can make an entry in the master-list.
What should the entry have in it? Certainly not the wallet itself, because that CAN be passed around. Probably you need a sublist that describes the transaction that just took place, so you would need a sublist containing [wallet-id, last-owner-id, current-owner-id, time-it-changed-hands] as the entries in the master global list.
From that you could at least conceptually be able to reconstruct who had the list first, second, third, .. or last, who has it now, anything you wanted. Or if you always did "lput" to put the latest event as the last item on the list, then you wouldn't even need the time-stamp, unless you lose information by sorting the list, because the first owner would be the first entry on the list that had that wallet-id. Problem solved, in concept. Still you might want to sort the list someday, so having the timestamp on it would allow you to recover the order later if you wanted to.
In conclusion of all that discussion, my suggestion to finding out who had wallet1 first would be this:
* get rid of the my-lists on every agent entirely.
Work with a single list defined as a global.
treat wallets as if they are real and only have one copy of a wallet at any one time.
define procedures "steal-wallet", "create-wallet" and "destroy-wallet" that move the wallet from one owner to another, and record the transaction as a sublist of 4 facts in the master list. The master list would be a list of lists then.
the master list might be named "transactions" because that's what it records.
then, conceptually, you would have all the information you need to answer any question about the life-history of a wallet or the life-history of a thief. You wouldn't have to maintain 20 different copies of the same information.
and it would be easy to look at all the thieves and see which one had the wallet, without needing to look at the transaction list. ( although, that information would correspond to the last entry in the transaction list about that wallet.)
Or -- maybe I totally misunderstand what these lists represent.
Passing the ball ( or wallet ) back to you.
Lists of agents and agentsets are two different data types in NetLogo (and can be converted with turtle-set and sort). The documentation states that you use lists for an ordered collection of agents and sets for an unordered collection. It appears that anonymous procedures available to lists makes lists more flexible than agentsets. On the other hand, using 'ask' in combination with agentsets is more common in the example models and has been stated to be more readable.
Can one translate any combination of list and anonymous procedure to a statement using an agentset and 'ask'? In particular, can you provide an equivelant of filter or map using ask and agentsets? Please advise some situations in which one or the other is more appropriate, and the benefit that the structure provides.
you use lists for an ordered collection of agents and sets for an unordered collection. I feel there is more to it though.
Ordered vs. unordered is an important difference, but there is another crucial one: lists can contain duplicate items, agentsets cannot.
I do not know how to properly implement an equivalent to filter or map using ask.
You don't need to implement those: they already exist!
The agentset version of filter is with:
my-agent-set with [ color = red ]
is the same as:
filter [ a -> [ color = red ] of a ] my-agent-list
The agentset version of map is of:
[ color ] of my-agent-set
is the same as:
map [ a -> [ color ] of a ] my-agent-list
And, as you may have intuited by now, ask is the equivalent of foreach.
Grasping these similarities is an important step towards NetLogo enlightenment. (Or even general programming enlightenment.)
The idea of unifying (or somehow generalizing) the syntax and primitives for these two types of collection has been discussed before (e.g., here and here), but that kind of big language change tends not to happen very often.
using agentsets (and 'ask') is more in line with the idea of Netlogo. It might be faster or easier to read.
As the code examples above nicely illustrate, agentsets do have a nicer syntax. And that's a good thing, since unordered collections of unique agents are usually what you need when doing agent-based modeling.
They're not inherently faster, though. Adding to them, in particular, is slower than adding to a list. To use a contrived example, it is much faster to do:
let my-list []
repeat 50 [ set my-list lput one-of turtles my-list ]
let my-agentset turtle-set my-list
Than to do:
let my-agentset no-turtles
repeat 50 [ set my-agentset (turtle-set my-agenset one-of turtles) ]
What is your experience on this matter?
Agentsets are what's needed most of the time, but lists are also needed once in while.
Jen's example of using them for implementing a memory is a good one, but there are other use cases. Hopefully, you'll know them when you see them.
If I switch to turtle/patch context and do something like "set pcolor green", in what order do they execute the commands? I tested it out with a wait in there to see if there was an obvious pattern, but couldn't notice any. Is there any difference between that and ask?
I doubt it's completely random, though. How's it actually being handled behind the stage?
It's random--about as random as things get in computer programming, I believe. The NetLogo User Manual says:
An agentset is not in any particular order. In fact, it's always in a random order. And every time you use it, the agentset is in a different random order. This helps you keep your model from treating any particular turtles, patches or links differently from any others (unless you want them to be). Since the order is random every time, no one agent always gets to go first.
I just looked quickly at AgentSet.java in the source code for a recent version of NetLogo (5.0.2), it and looks to me like the order is randomized using a Mersenne Twister algorithm, which is usually considered to be quite good for randomization.
If you want the turtles/patches/links in a particular order, you can use sort, or select elements using e.g. with, or convert the agentset into a list using [self] of <agentset>, for example.
I am new to NetLogo and I have some questions about the following piece of code:
people-own [
walker-type ;; can be "cautious", "adaptive" or "reckless"
walked-through-red?
own-profit
adaptive-threshold-time-gained
adaptive-threshold-time-gained-people-crossing
adaptive-gone-reckless
cooldown
]
With an OO background, I see this as some kind of enumeration of the properties of an object (the people breed). You can clearly see that there are three types of people: cautious walkers, adaptive walkers and reckless walkers. Also, the properties beginning with adaptive (adaptive-threshold-time-gained and such) have only meaning when the current person is adaptive.
I would expect that there is some way to express this more elegantly. In an OO programming language you would use inheritance to create three subclasses (one for each walker-type), but for so far I know that doesn't exist in NetLogo.
What is the recommended way of expressing this?
Lack of inheritance (perhaps as sub-breeds) is a serious limitation of NetLogo, although in the end it has only occasionally mattered to me. There are a couple possible work-arounds, depending on the application.
If you just want some different data attributes, and the related types are the only turtles in the simulation, you can have turtles-own the common characteristics and have breeds-own only the type specific characteristics.
If the data attributes are all shared but the behavior differs, you can create your own agentsets (in your case, subsets of people) and call different procedures on each agent set (or write procedures that branch on a member? test). Unfortunately, these agentsets will have to be explicitly augmented if any new members are created, so you lose that nice "special agentset" feature of breeds.
hth.