In netlogo I have a procedure that calls another procedure. How can I go about getting the value
for example, I have two breeds of agents, a hub and a link. A hub has a local variable called 'budget' and I'm trying to modify its value.
hubs-own [
budget
]
to go
ask hub 0 [
do-ivalue
]
end
to do-ivalue
ask links [
;; I'm trying to set the local variable budget of the hub that's calling this link
set self.budget newvalue ;; this is obviously wrong, how can I fix this?
]
end
what you want to do is use is 'myself', it refers to the caller (asker): the one who asked to run the code where the 'myself' is located.
to do-ivalue
ask links [
ask myself [set budget 10] ]
end
The 'self' refers to the agent running the code. It is similar to 'this' in Java.
hmm.
not sure why u want to do it this way..
what u can do for now is
ask links[
let new_value new_value_from_link
ask hubs[
set budget new_value
]
]
Related
I was trying to personB's own variable to update in personA's own list type variable. when I tried to run this code i recived an error message "PERSONB breed does not own variable LEDGER
error while personbs 1 running LEDGER, called by procedure UPDATE-LEDGER...."
I cant change the ownership(If I make it global others can alter). how can I solve this?
My code is:
breed [personAs personA]
breed [personBs personB]
personAs-own [
wallet
ledger
]
personBs-own [
packid
batch-num
]
to start
ca
create-personAs 1 [
setxy random-xcor random-ycor
set shape "person"
set ledger []
]
create-personBs 1 [
setxy random-xcor random-ycor
set shape "person"
set packid 10
set batch-num who
]
update-ledger
end
to update-ledger
ask personBs [
set ledger fput (list packid batch-num) ledger
]
end
[Before starting: please note that in NetLogo breeds are defined first in their collective form and later in their individual form, e.g. breed [cats cat] instead of breed [cat cats], so you should change your breeds declarations accordingly. I'll give my answer as if you used the correct declaration, e.g. breed [personAs personA]. Also, note that breeds in NetLogo are not sensible to lower/upper case, so in general you might also want to give more meaningful names to make it easier to read]
--
It is possible to change turtles' breed by just asking them to
set breed newbreed
This will change their breed and, accordingly, all their breed-own variables (i.e. the turtle will lose its previous breed's variables and will gain its new breed's variables).
However your problem seems to be more fundamental: why did you make ledger a personAs-own variable if you want personBs to use set ledger? This is the crucial point.
There are two possibilities here:
You want each turtle to have a ledger to operate on. In that case, ledger must not be a personAs-own variable; it has to be a turtles-own variable (or, if in your full model you have other breeds who do not need ledger, then make it both a personAs-own and personBs-own variable). In any case, no global variables involved (a global variable only has one value for everyone, so that's not what you need).
You want personBs to be able to operate on the ledger of personAs. In that case, personBs will have to ask personAs to modify their ledger; or, alternatively, some personBs can operate on the ledger of some personAs by indeed using the of reporter (see here); for example:
; Solution with 'ask':
ask one-of personBs [
ask one-of personAs [
set ledger 10000
]
]
; Solution with 'of':
ask one-of personBs [
set [ledger] of one-of personAs 10000
]
Important update
Your expression "If I make it global others can alter" suggests me that you're thinking in terms of other programming languages, where you classify variables based on the level of access to that variable that other parts of the programme have.
Note that this is not the case in NetLogo: all parts of the programme (in this case: all agents) have access (even if indirect) to every variable through ask and/or of. No matter whether a variable is turtles-own, links-own, breed-own or patches-own. Every agent can read any other agent's variables. But also: every agent can modify any other agent's variables (see the code examples that I made regarding point 2 above). Therefore, making a variable something-own simply means that those are the agents carrying that variable.
In my study, I'm trying to build a simulation representing of a real work setting, with the aim of creating knowledge on how make people feel better at work.
In particular, I'm modelling a scenario where people work for more than one team (do you work on only one project at a time? Many don't...). To do this, I'm working with NetLogo.
I'm having a problem with an ASK to a specific agent of a custom link-turtle-set. The point is that sometimes it reports an error, saying that "ASK expected input to be an agent or agentset but got NOBODY instead", but it should not arrive to that "ASK" without the agent to exist! What am I doing wrong?
The function is the following:
to TeamRecruiting
;; I ask non-complete teams to...
ask teams with [ teamsize != (count membership-neighbors) ]
[
;; ... count how many individuals they have...
let actualteammembers count membership-neighbors
;; ... to save locally how many individuals they can share...
let teamoverlap overlap
;; ... their target size...
let neededsize teamsize
;; ... and their identity.
let teamwho who
;; then I ask those individuals that have not yet more things than they can handle...
ask individuals with [ indMTM != (count membership-neighbors) ]
[
;; ... to save locally who they are...
let indwho who
let createdalink 0
;; ... then if some conditions have been met ...
if(some conditions)
[
;; I create a link (of my specific type) with the team...
create-membership-with team teamwho
;; I do the following because more than one individual could join the team teamwho in the same run of the function
ask team teamwho [ set actualteammembers (actualteammembers + 1) ]
set createdalink 1
]
;; if the association occurred, ...
if(createdalink = 1)
[
;; we ask all other teams to evaluate if the new connection violates their maximum overlap constraint between the team I am considering from the beginning of the function, and all other teams, in other words...
ask teams with [ who != teamwho ]
[
let numpaths 0
let team2who who
;; I count how many individuals say that they are shared by the two teams
ask individuals
[
if((membership-neighbor? team teamwho) and (membership-neighbor? team team2who)) [ set numpaths (numpaths + 1) ]
]
;; ... and if the number of paths is more than the maximum allowed overlap...
if(numpaths > teamoverlap)
[
;; I take the connection away...
ask membership teamwho indwho [ die ]
;; and I reduce the actual number of team members
set actualteammembers (actualteammembers - 1)
]
]
]
]
]
end
Thank you for your precious help!
I think that the problem is likely to be in the way you refer to the link you are asking to die. membership is an undirected link and so which agent is end1 and which is end2 depends upon the order in which the agents were created. The one with the lower who number is end1 and the other is end2. So, if the team agent was created after the individual agent, that particular link would be membership indwho teamwho. In general, using who numbers at all is bad practice, but the same problem would arise if you used the team and individual agents themselves rather than their who numbers.
Someone with more experience in the use of undirected links than I might have better advice on how to easily refer to an undirected link when you don't know offhand which agent is the older, but something like
ifelse (indwho < teamwho) [
ask membership indwho teamwho [ die ]
]
[
ask membership teamwho indwho [ die ]
]
should work. Using directed links obviates this problem as the creator agent is always end1 and the target agent end2. So, if membership links always are created by the individual, you'll always know that the individual is at end1.
Hope this helps.
Charles
(Due to Netlogo lacking debugging tools...)
I would like some code to somehow tell what agent context it is in (Observer, turtle id, link, patch etc.). Something like:
carefully [set id self] [set id "Observer]
But Netlogo does not allow this as the syntax checker dissallows self here.
Any ideas? An extension?
Thanks
You can use show to print the context, of course. To actually get the value, you can cheat the syntax checker using runresult
carefully [ set id runresult "self" ] [ set id "observer" ]
Update:
This comment on github reminded me that tasks can also be used and would be somewhat preferable:
carefully [ set id runresult task [ self ] ] [ set id "observer" ]
The netlogo docs give the following example
show count turtles-here
=> 10
show count other turtles-here
=> 9
and the documentation says the "other" command excludes "this" agent. My question is ... WHICH agent? Seems like this command can be run in the observer context and so no agent. Or at least in this example, the context could be a patch context in which case the "other" would exclude ALL the turtles? Is there some mechanism to set the context for a particular agent? Maybe:
ask agent [
show count other turtles-here
]
in which case why didn't the NetLogo code snippet include that?
The agent excluded is the agent being asked. ask, ask-concurrent, and of set the context. For example,
ask turtle 0 [ show count other turtles ]
counts all turtles except for turtle 0.
ask turtles [ show count other turtles ]
iterates over each turtle individually. In each iteration, other excludes the current turtle.
other never excludes agents of a different type. That is,
ask patch 0 0 [ show count other turtles ]
will just count all the turtles since none of the turtles are patch 0 0.
The agent of the current context can be referred to with self. The agent that other excludes will always be self. Thus,
ask agents [ show count other agents ]
is exactly equivalent to
ask agents [
let this-agent self
show count agents with [ self != this-agent ]
]
(note that this can be expressed more succinctly using myself, but since myself is way more confusing, and way worse named, than other I'm avoiding it here)
Seems like this command can be run in the observer context and so no agent.
This is in fact a bug! I've created an issue for it here: https://github.com/NetLogo/NetLogo/issues/757
How is it possible to change specific variable of an agent by passing variable name to a function?
for example I have turtles with variable MONEY and the following function:
to setVariable [varname varvalue]
[
ask one-of turtles [ set varname varvalue ]
]
end
Now I want to run:
observer> ask one-of turtles [setVariable MONEY 100] ;; I need to ask via another turtle since I cannot use MONEY directly in observer context
And it does not set my variable without giving any errors.
Interestingly, you can read a variable in similar manner:
to showVariable [varname ]
[
ask one-of turtles [ show varname ]
]
end
So the question here is how to "convert" my function input into turtle's variable name it would recognise well for SET purposes.
PS: I don't want to use run function as it would slow down the model.
In a similar situation where there are a number of possible options, I create a task for each and put them in a lookup table (using the table extension) with a string key for each. Then I can lookup the appropriate task for any key. It saves having the nested if/else structures, but I haven't investigated the efficiency of the table lookup.
You're correct that run with strings would slow down your model, but if you use run with tasks, it won't.
Here's your setVariable procedure rewritten to use tasks:
to setVariable [setter value]
ask one-of turtles [ (run setter value) ]
end
When you call it, the call will look like:
setVariable task [ set money ? ] 100
But this won't help you if at the call site, there's no way to avoid using strings.
If you must use strings, and it must be fast, then you have no choice but to write out a big ifelse chain that lists all of the variables that you need to support:
to setVariable [varname varvalue]
ask one-of turtles [
ifelse varname = "money"
[ set money varvalue ]
[ ifelse varname = "food"
[ set food varvalue ]
...
]
end
For reading variables, instead of setting, you can safely use runresult with a string containing the variable name without needing to be concerned about performance, since runresult caches the compiled strings, so it will be fast since you'll be passing the same strings over and over. (The setting case is different because the strings you'd be passing to run would be different all the time.)