Associating turtles and links through attributes - netlogo

I have a road network consisting of directed links between nodes. Cars drive over the network on paths that are randomly generated at setup but remain fixed for the duration of travel. I want to count the number of cars on any given link:
breed [cars car]
breed [road_nodes road_node]
directed-link-breed [road_segments road_segment]
cars-own [current-road-segment]
road-segments-own [number-cars-here]
I'd like the value of number-cars-here for road_segment x y to be number of cars with current-road-segment = "road_segment x y". Is there any way to do this? Thanks.

It is probably best to count them all at one go:
to count-cars ;;observer proc
ask road_segments [set number-cars-here 0]
ask cars [
ask current-road-segment [
set number-cars-here (number-cars-here + 1)
]
]
end

Related

Netlogo: Making a turtle interact with anotherone after evaluating similarity in a given variable

I have several turtles each with three variables opinion1, opinion2 and opinion3. I need them to:
identify which of these three variables has the highest value
find another turtle in their network with a value at least as high
as the one found in 1.
update its own value found in 1. with
respect to that of the turtle found in 2.
What I have done doesn't really work because it only updates looking at o1 without really having a look at which of the tree (opinion1, opinion2 or opinion3) is the highest and THEN looking for a neighbour.
to update-opinion
ask turtles [
let my-nearby-turtles nw:turtles-in-radius 1
let my-opinion1 opinion1
set neighbour one-of my-nearby-turtles with [ opinion1 > my-opinion1 ]
if neighbour != nobody [
let opinion_n [opinion1] of neighbour
set opinion1 ((opinion1 + opinion_n) / (2))
]
]
end
I don't know a simple way to do this with unique variables like opinion1 etc, but maybe having a list of opinions instead of individual variables for each opinion will work. For example, with this setup:
extensions [ nw ]
turtles-own [
opinions
]
to setup
ca
resize-world -5 5 -5 5
set-patch-size 30
crt 30 [
set shape "dot"
set opinions n-values 3 [ precision random-float 10 2]
set color scale-color blue sum opinions -5 35
while [ any? other turtles-here ] [
move-to one-of neighbors4
]
]
ask turtles [
create-links-with turtles-on neighbors4
]
reset-ticks
end
You get something like this:
Where each turtle has an opinions list variable that is three items long. Now, you can have each turtle determine its highest opinion value using max, get that maximum values index position in the list using position, and then query that turtle's neighbors to see if any of them have a higher value in the same index position. If they do, modify your asking turtles opinions list using replace-item to be the average of the two values:
to go
ask turtles [
; Get adjacent turtles
let my-nearby-turtles nw:turtles-in-radius 1
; Identify the highest highest value variable of
; the current turtle, and get its list position
let my-opinion max opinions
let my-op-ind position my-opinion opinions
; Pick one of the turtles whose value in the same indexed
; position is higher than my-opinion
let influence one-of my-nearby-turtles with [
item my-op-ind opinions > my-opinion
]
; If that turtle exists, update my own opinions list as appropriate
if influence != nobody [
let new-opinion precision (
( [ item my-op-ind opinions ] of influence + my-opinion ) / 2
) 2
set opinions replace-item my-op-ind opinions new-opinion
]
set color scale-color blue sum opinions -5 35
]
tick
end
Hopefully that is sort of on the right track, not sure if a list will work for what you need. If you must have the variables as standalone values at each tick, I suppose you could convert them to a list then follow the procedure above. If you only need them for output, you could just update your unique variables as needed based on the values in the list (as long as you are consistent with the order).

Is it possible to have enumerated data types in NetLogo?

Is it possible to have enumerated data types in NetLogo?
Let's say that I have a model of marital status change.
An agent can have 3 marital status states: single, married, divorced.
I would like to map those states into numbers so that it takes less memory when executed.
single = 1
married = 2
divorced = 3
so that I can just do
ask agents with [ marital-status = single ][ get-married ]
I have found a trick to do that with "to-report"
eg:
to-report single
report 1
end
But this means I have to create many to report functions if I were to have many categories in many variables. Is there a better workaround than this?
Thanks :)
How big is your model? My understanding is that an agent attribute is minimum 8 bytes anyway (see https://github.com/NetLogo/NetLogo/wiki/Optimizing-NetLogo-Runs)
I can't think of a natural way to do this. However, if you really wanted to, this workaround would work: store the marital status as 0, 1, 2. Also store a global variable called marriage-status-map and use the item primitive. So it would look like this:
globals [ marriage-status-map]
turtles-own [ marriage-status ]
to testme
clear-all
set marriage-status-map ["single" "married" "divorced"]
create-turtles 10
[ set marriage-status random 3
setxy random-xcor random-ycor
set color blue
]
ask turtles with [item marriage-status marriage-status-map = "single"] [set color red]
end

adding agentset from different agents togother into a let

my model is a network of agents connected to each other with links.
I try to create a agentset from the neighbors of an agents and their neigbors and so on (I need this to assign different values to it).
However when I create a let with the agentset in it. the agents asked to make this agentset all have their own, this is so far so good. But when I want the original agent to ask him his second line neighbors he just returns an agentset from one of this neighbors instead of the combined agentsets of all his second line neighbors
I want the neighbors to store their own neighbors into a agentset with all the neighbors from the different agents in that set.
I cant ask the let agentset to simple do turtleset current-agentset new-agentset since in a let you cant ask to let variable. So a code which would normally be set second-neighbors (turtle-set second-neighbors other-nieghbors doesnt work since I cant ask second-neighbors already in a let
I also cant make this a global or somethins since it is agent specific.
the code I have so far looks like this
ask companies [
let this-company self
let b link-neighbors
ask b [ let c link-neighbors with [self != this-company]
ask c [ let d link-neighbors with [not member? self b]
ask this-company [
set iburen b
set iiburen c
set iiiburen d
]
]
]
]
so what I want is that all the agents in the agentset c report their link-neighbors like they do now. But also store these link-neighbors into a new agentset which has all the link-neighbors of all the agents in c. like a simple i i + 1. but than with turtle-set (what I have) (what is new from the next agent asked)
the same goes for d
If I run the model now agents report different agentset almost every tick. They just pick one agentset from any of these agents instead of combining them all togother.
Here is what I think you need:
extensions [ nw ]
breed [ companies company ]
companies-own [
buren ; a list of agentsets, with one item for each "level" of neighbors
]
to setup
clear-all
; create a random network and lay it out:
create-companies 20 [ create-links-with n-of 3 other companies ]
repeat 30 [ layout-spring turtles links 0.2 5 1 ]
let num-levels 3
ask companies [
let all-neighbors other nw:turtles-in-radius num-levels
set buren (list) ; initialize to empty list
foreach range num-levels [ i ->
let neighbors-at-this-level all-neighbors with [
nw:distance-to myself = i + 1
]
set buren lput neighbors-at-this-level buren
]
]
; demonstrate how to access the levels (sorted only for display purposes)
ask one-of companies [
show sort item 0 buren ; first level neighbors
show sort item 1 buren ; second level neighbors
show sort item 2 buren ; third level neighbors
]
end
This might not be the most efficient code possible, because it goes through the list of all neighbors once for each level, but unless you have a humongous network, you should not notice.
If you really wanted to use variables like iburen, iiburen and iiiburen, you could always alias the items of the list:
set iburen item 0 buren
set iiburen item 1 buren
set iiiburen item 2 buren
...but I don't recommend it. Having your agentsets in a list should encourage you to think of your levels in a more general way.

How to get the top 10 turtles sorted by reverse in-degree centrality?

I want to get a list of top ten turtles in terms of their degree centrality. I have tried but I am not getting the required result.
In the code below, I am storing centrality in a list and then reverse sorting it. However, it is storing centralities only. I want turtles ordered in terms of their centrality. I also have tried saving turtles on the list and have used sort-by but got an error.
I also have tried to get agents using turtles with max degree centrality, but the problem arises when several nodes have the same centrality. I want to do this in an efficient manner.
globals [indeg]
turtles-own [centrality]
to setup
ca
crt 160
ask turtles [
set indeg []
fd random 15
]
ask turtles with [color = red] [create-links-to other turtles with [color = blue]]
ask turtles with [color = green] [create-links-from other turtles with [color = yellow]]
inf
end
to inf
ask turtles [
set centrality count my-in-links
set indeg lput centrality indeg
]
set indeg sort(indeg)
print "indeg"
print reverse(indeg)
print max(indeg)
end
Here are three different ways to get that information, with potentially slightly different performance and results:
to setup
clear-all
create-turtles 160 [ forward random 15 ]
ask turtles with [color = red] [create-links-to other turtles with [color = blue]]
ask turtles with [color = green] [create-links-from other turtles with [color = yellow]]
let top-10-a reverse sort-on [ count my-in-links ] max-n-of 10 turtles [ count my-in-links ]
show-results top-10-a "Top ten turtles using max-n-of:"
let sorted-turtles reverse sort-on [ count my-in-links ] turtles
let top-10-b sublist sorted-turtles 0 9
show-results top-10-b "Top ten turtles from sorted list:"
let top-10-c filter [ t ->
[ count my-in-links ] of t >= [ count my-in-links ] of item 9 sorted-turtles
] sorted-turtles
show-results top-10-c "Turtles with top ten centrality:"
end
to show-results [ turtle-list title ]
print title
foreach turtle-list [ t -> ask t [ show count my-in-links ] ]
end
The first (method "a") and most obvious is to use NetLogo's max-n-of primitive. That primitive gives back an agentset (not a list), so if you want an agentset, that's the way to go.
Your question seem to indicate that you ultimately want a list of turtles sorted by decreasing centrality, so you have to use reverse sort-on [ count my-in-links ] on the result of max-n-of, which is what I'm doing above.
Another approach (method "b") would be to sort all turtles by their centrality, store the resulting list in sorted-turtles variables and then take the first 10 of that. That method is a bit more intuitive but could be slower than the max-n-of method since it has to sort the whole list. Depending on how many turtles you have, however,the difference could be negligible.
One thing the first two methods have in common is that the ties are broken randomly. This means that if you have, let's say, three turtles that have a centrality worthy of position number ten in your top ten, you'll only get one of those. (Given the way you construct your network in the example from your question, this is very likely to happen.) If you want your top ten to potentially include more than 10 turtles in case of equality, you need to use method "c".
The last method sorts the whole, look at the centrality of the tenth turtle in that list, and filters the list to keep only the turtles with centrality greater or equal to that one.

NetLogo : what is a good way for Storing link values and deducting the dead link values without calling links more than 1 time?

I am sorry to keep asking about links, but one of the features that I am going to add to my model is considering collective mutual relationship of people of different villages in village's future relationships,
I have a few thousand links and it's not efficient to call links and get their value whenever the village wants to make a decision (the decision is made every 48 ticks at clock 0)
Agents own belongs_to which is one one "Village1" Village2" Village3" or "Village4"
Links have a Value of Relationship.
This is the function I used to update links value:
to Update_link_Values [Other_Agent Value]
if self != Other_Agent
[
ifelse out-link-neighbor? Other_Agent
[
ask out-link-to Other_Agent
[
set Value-Of-The-Relationship Value-Of-The-Relationship + Value
set-List-of-Mutual-Obligations
]
]
[
create-link-to Other_Agent
[
set Value-Of-The-Relationship Value-Of-The-Relationship + Value
set-List-of-Mutual-Obligations
]
]
]
end
if I use following formula to store sum of relationship values for different villages it takes 0.003 MS to calculate all mutual relationship values
if [belongs_to] of end1 = "Village1" and [belongs_to] of end2 = "Village2"
[
set List-of-Mutual-Obligations replace-item 0 List-of-Mutual-Obligations (item 0 List-of-Mutual-Obligations + Value-Of-The-Relationship)
]
While this one takes 1.002 MS to execute,
if [belongs_to] of end1 = "Village1" and [belongs_to] of end2 = "Village2"
[
set List-of-Mutual-Obligations replace-item 0 List-of-Mutual-Obligations sum [Value-Of-The-Relationship] of links with [[Belongs_to] of end1 = "Village1" and [Belongs_to] of end2 = "Village2"]
]
my problem with first version is that it adds the value of each link to sum of all values of previous links in that group and does not consider if a link is dead or not, but second one is more accurate.
Since Value of relationship is link property I don't want to ask links more than once in the code and I update the sum values whenever a link is being changed or created.
I thought it might be better to update the values every 48 ticks , since many agents might call this function every tick, but for doing that I have to call links and I am not sure which way is better?
Update:
I have changed my code so I will calculate the links I need whenever a decision is made:
to-report Value-of-Mutual-Obligations [Village1 Village2]
report sum [Value-Of-The-Relationship] of links with [[Belongs_to] of end1 = Village1 and [Belongs_to] of end2 = Village2]
end
Another way of thinking of it.
Create a breed for the Villages.
breed [ villages village ]
Create new link breeds, one for the villages, and one for people. (you can't use the built-in links breed when you have any custom links breed):
directed-link-breed [ village-links village-link ]
directed-link-breed [ person-links person-link ]
give village-links a variable VALUE-OF-MUTUAL-OBLIGATIONS
give the villages a variable VALUE-OF-SELF-OBLIGATIONS -- this is to handle cases where both persons are from the same village -- sadly, netlogo does not allow self-links.
Create a village turtle for each village. They can be hidden. You can apply the name of the village ("Village 1") to the label of the village.
Link all the villages to each other, in both directions.
A person's belongs-to contains a village turtle.
e.g. to randomly assign a village:
set belongs-to one-of villages
So, now, rather than having to calculate the value of mutual obligations wholesale, you can alter it directly, as it changes.
Whenever you change the value of a link, you can also change the VOMO variable for the village link. You use the who numbers of the villages to figure out the link ID, or to use the SELF-OBLIGATIONS version in that special case.
to update-relationship-value [ #value ] ;; run by the person's LINK
set value-of-the-relationship value-of-the-relationship + #value
let from-village [ belongs-to ] of end1
let to-village [ belongs-to ] of end2
ifelse from-village != to-village
[ ask village-link ([who] of from-village ) ([who] of to-village)
[ set value-of-mutual-obligations value-of-mutual-obligations + #value
]
]
[ ask from-village ;; update self-obligation value
[ set value-of-self-obligations value-of-self-obligations + #value
]
]
end
So, you only touch the value of mutual obligations once, when you update the relationship value.
You could probably make this slightly more efficient by extracting the village link update code so that it's run by the turtle, not by the link, so that you don't have the extra "[stuff] of end1" stuff.