Selecting an element in a list - netlogo

I have a list made up by two turtles (for simplicity, houses and landlords).
Thanks to some suggestions that were provided me here, I selected the house with maximum price from the list, but unfortunately the landlord is not the owner of that house, but only the turtle selected one tick before.
I understood that something is going wrong with the definition of this turtle.
What I wrote, after the suggestions, is:
let selected_house max-one-of turtle-set my-list [price]
let selected_landlord [my-landlord] of selected_house
print (word "Landlord" [selected_landlord] of selected_house)
let new_list (list selected_house selected_landlord)
print (word "Landlord " selected_landlord "of house: " selected_house " by price: " [price] of selected_house)
but if, let's say, I have:
List:
"Landlord 2 is the owner of house 4 by price 400000"
"Landlord 5 is the owner of house 1 by price 100000"
"Landlord 4 is the owner of house 3 by price 300000"
and then I use selected_house/landlord to select the owner of the house with highest price, I should get (house 4, landlord 2); however, I am getting (house 4, landlord 5), i.e. the landlord selected one tick before.
I defined the landlord and house as follows (I have similar exercises, but on different topics):
if breed = landlords [
hatch-houses n_house [
set price precision (random-float 1) 3
set this-house self
set this-landlord myself
ask myself [
set my-list fput (list this-house this-landlord) my-list
]
]
where this-house and this-landlord are globals and my-list is landlords' own.
Could you please help me to understand and fix the issue with this part of code?
I thought that, as I am creating the list with the first element = house and the second element = landlord, it could be possible add some condition to make the selection as easy as possible (for example, once selecting the first item, i.e. house with highest price, set the second item of each element in the list as landlord of a house).

I'm not sure why this-house and this-landlord are globals, and I think (without the full code to go on) that this may be your problem. If I understand your model, each landlord has a set of houses, and you want to be able to find the most expensive house and the landlord that owns it. If each house keeps track of its landlord and price, and each landlord keeps track of their houses, then that should allow you to link any house to its landlord, or to look at all the houses that a landlord owns.
The following model perhaps will give you one idea of how to proceed. It creates landlords, each of which then creates houses with a random price. It then finds the most expensive house and its landlord. Then for each landlord, it finds that landlord's most expensive house. The landlord could keep a list of houses with [house landlord], but the second item would be the same for all the landlord's houses.
breed [landlords landlord]
breed [houses house]
landlords-own [my-houses my-house-list]
houses-own [price my-landlord]
to test
clear-all
create-landlords 10
ask landlords [
hatch-houses 5 [
set price precision (random-float 1) 3
set my-landlord myself
]
set my-houses houses with [my-landlord = myself]
]
let most-expensive max-one-of houses [price]
show (word "The mostexpensive house is house " most-expensive " owned by " [my-landlord] of most-expensive " with price =" [price] of most-expensive)
ask landlords [
let my-most-expensive max-one-of my-houses [price]
show (word "landlord " self "'s most expensive house is house " most-expensive " with price =" [price] of my-most-expensive)
]
end
On the other hand, you could keep a list of all houses across all landlords as a global, and if you run list-houses after test, you will get such a list, which you can then sort by price, landlord, or whatever.
globals [house-list]
to list-houses
set house-list []
ask houses [
set house-list fput (list self my-landlord price) house-list
]
show house-list
let sorted-by-price sort-by [[a b] -> item 2 a > item 2 b] house-list
let most-expensive first sorted-by-price
show (word "the most expensive house is house " item 0 most-expensive " with owner " item 1 most-expensive " and price " item 2 most-expensive)
end

Related

Netlogo: How to subset with row and column indexes

Could someone help me out with the code on reading in data in Netlogo? I am trying to choose one element in multiple lists to assign it to the turtle as a variable (I have the data in a rectangular table read from a csv file).
In my current code, it reads as I want but the problem is it is reading only elements of one last row instead of iteratively reading elements (across columns) of all rows. What I need is to read one element of each row at a time.
here are some rows of my data
Here is what I have tried so far:
let residents-file "mock-data.csv"
let residents-list []
set residents-list csv:from-file residents-file
foreach residents-list [ ?1 ->
let hh-col ?1row
let residents-to-create 1
create-residents residents-to-create [ setxy random-xcor random-ycor ]
ask residents [
set shape "person"
set color 9
set ID item 0 hh-col
set occupancy item 1 hh-col]]
It looks like the issue is that you are using create-residents to create n residents, but then asking all residents to do something. In other words, no matter which row is currently being processed, all of the existing residents (whether created in this iteration or created in previous iterations) are being asked to pull the values from the row that is being processed on the current iteration.
The easiest way to fix this is probably just to have each resident pull the values as it's being created.
With this toy version of your dataset:
id occupancy
1 owner
2 renter
3 owner
4 renter
5 owner
Here is a simplified example:
breed [ residents resident ]
residents-own [ id occupancy ]
extensions [csv]
to setup
ca
let residents-file "mock-data.csv"
let residents-list but-first csv:from-file residents-file
foreach residents-list [ cur-row ->
create-residents 1 [
set id item 0 cur-row
set occupancy item 1 cur-row
]
]
ask residents [
print ( word "My who is " who ", my id is " id ", and my occupancy is " occupancy )
]
reset-ticks
end
Output should look something like:

How to select an object shared with my neighbours

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

Associating turtles and links through attributes

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

How to create pairs in netlogo

I am trying to make connection between agents. I have created 3 breeds of agents: firms, officers and citizens ( each breed has 10 agents), and I need to create pairs. Each pair involves: one firm, one citizen and one officer ( agents are chosen randomly). I also need that all agents will create pairs.
breed [ firms firm]
breed [ officers officer]
breed [ citizens citizen]
;; then I need to create pairs, and If one agent of the pair is firm then, firm can dicide to bribe or not, if not, firm earns 30, officer earns 0 and citizen earns 10:
to go
if ticks mod 3 = 0
[
ask turtles
[
if breed = firms
[
if bribe? = false
[
set budget budget + 30
output-print (word " firms " budget)
ask other turtles
[
if breed = officers [ set budget budget + 0
output-print (word " officers " budget)]
if breed = citizens [ set budget budget + 10
output-print (word " citizens" budget)]
]
stop
]
]
]
]
;; then go other ticks, where citizen and officer decide to accept bribery or punish for accpeting bribery....
You say “each pair involves: one firm, one citizen and one officer”. I'd call that a triplet, or just a combination rather than a pair; “pair” always means two, never three.
Here's some sample code that forms all possible triplets and then does something approximating your description:
ask officers [
let this-officer self
ask citizens [
let this-citizen self
ask firms [
if bribe? [
set budget budget + 30
ask this-citizen [
set budget budget + 10
]
]
]
]
]
I wasn't able to understand everything you said about what you're trying to do. But hopefully the above code is close and illustrates the principle of nesting ask in order to form all possible combinations.

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.