Create links according to turtle's attributes - netlogo

I have two turtle breeds (products and consumers) each with a 3-dimension list that defines their needs (consumers) and their attributes (products).
What I'd like is to have each consumer (i) look for a product that satisfies all their needs and create a link with them. If that product does not exist, I'd like them to (ii) drop the one need with the lowest value and look for a product that satisfies the other two. If that product does not exist, then I want them to (iii) look for another one that only satisfies the need with the highest value.
So say that consumer 20 has needs [0.2 0.5 0.3]. If they find a product whith exactly the same list of attributes [0.2 0.5 0.3] I want the link to take place. If there's no such product then I want the consumer to ignore the lowest value (0.2 in the example) and look for a product that has attributes [xx 0.5 0.3], where xx stands for "whatever".
Using examples from elsewhere here in SO, I have cobbled up the following code that (almost!) does the first part of the trick (i), but can't manage to do (ii) and (iii) despite multiple efforts. Would anyone have an indea on how to do this?
breed [consumers consumer]
breed [products product]
consumers-own [
needs
]
products-own [
attributes
number-buyers
]
to setup
ca
create-consumers 100 [ setxy random-xcor random-ycor]
create-products 100 [ setxy random-xcor random-ycor]
set-default-shape consumers "person"
set-default-shape products "box"
ask consumers [
set needs n-values 3 [ precision (random-float 1) 1 ]
]
ask products [
set attributes n-values 3 [ precision (random-float 1) 1 ]
]
reset-ticks
end
to go
buy
tick
end
to buy
ask links [ die ]
ask consumers [
carefully [ create-link-with one-of products with [reduce and (map = attributes [ needs ] of myself)] ] [ show "how do I find a sub-optimal product by ignoring my need with the lowest value ?" ]
]
ask products [
set number-buyers count link-neighbors
]
end

You are overthinking the full match - just check if the two lists are the same. However, the almost match is a bit more complicated. Here is a complete example model that finds the position in the list of the lowest and then checks that the other items are the same.
breed [consumers consumer]
breed [products product]
consumers-own [
needs
]
products-own [
attributes
number-buyers
]
to setup
clear-all
ask patches [set pcolor white]
create-consumers 10
[ setxy random-xcor random-ycor
set shape "person"
set color blue
set needs n-values 3 [ one-of [1 2 3] ]
]
create-products 10
[ setxy random-xcor random-ycor
set shape "box"
set color red
set attributes n-values 3 [ one-of [1 2 3] ]
]
reset-ticks
end
to go
ask consumers [buy]
tick
end
to buy ; set up as turtle procedure for testing purposes
ask my-links [ die ]
let candidates products with [attributes = [needs] of myself]
ifelse any? candidates
[ create-link-with one-of candidates ]
[ type self type " attributes: " type needs print " no matches"
let lowpoint position (min needs) needs ; note will take first if two equal min
set candidates products with
[ ((item 0 attributes = item 0 [needs] of myself) or lowpoint = 0) and
((item 1 attributes = item 1 [needs] of myself) or lowpoint = 1) and
((item 2 attributes = item 2 [needs] of myself) or lowpoint = 2)
]
ifelse any? candidates
[ create-link-with one-of candidates ]
[ print "no almost-match available" ]
]
end
I created the agentset (called candidates) of potential products to link to and then created the link. This makes the code much more readable. It also allows the if any? construction if no matches were found. And it also makes it easier to debug because you can put print statements reporting numbers of matches and similar. I recommend that you always do this if you are applying some sort of condition that restricts the choices.
Also, you have a three item list with 10 possible values for each item. This means there will be 1000 combinations. You only have 100 consumers and 100 products, so matching will be fairly rare.

Related

Linking turtles to another turtle with highest value in NetLogo. Limit the number of links

I am a beginner with NetLogo and I am trying to ask some turtles (students from different social classes) to link to other turtles (schools). What I would like is for the working class students to look for the school with the highest achievement which is at the same not expensive and has not reached the max number of links allowed. If the desired school has reached the max number of links allowed I want the student to look for the next school with the highest achievement which has not reached the max number of links allowed and so on.
This is the code. I get the following message "ANY? expected input to be an agentset but got the turtle (school 1) instead."
breed [schools school]
breed [upperclass upperclass-student]
breed [workingclass workingclass-student]
upperclass-own [achievement enrolled? target]
workingclass-own [achievement enrolled? target]
schools-own [schoolachievement expensive? ]
to setup
clear-all
set-default-shape schools "house"
set-default-shape upperclass "person"
set-default-shape workingclass "person"
ask patches [ set pcolor 8 ]
create-schools num-of-schools [ setxy random-xcor random-ycor set schoolachievement random-normal 5 1
set expensive? one-of [ true false ] ]
create-upperclass num-of-upperclass [ set color white setxy random-xcor random-ycor set achievement
random-normal 5 1 ] ;Students from upper class have higher achievement
create-workingclass num-of-workingclass [ set color red setxy random-xcor random-ycor set achievement
random-normal 4 1 ]
end
to go
ask workingclass [
choose-school ]
end
to choose-school
if breed = workingclass [
set target one-of schools with-max [ schoolachievement ] with [ expensive? = false ] ]
if any? target with [ count link-neighbors < max-link-count ] [
create-link-with target ]
set enrolled? TRUE
end
Your problem is the difference between an agent and an agentset, which is a somewhat subtle problem. The with-max returns an agentset - a set of agents (in this case turtles). That agentset can have 0 members, 1 member, 2+ members but is a set even if it is empty. However, the one-of selects one agent from the agentset and returns it as an agent, not an agentset. That is, NetLogo knows anything that is returned by one-of must be exactly one agent. At this point, primitives that are for agentsets (like any?) will throw an error unless they can also be used on individual agents.
So, back to your code. I like the readability of checking whether there are viable schools and then selecting one, which is what I think you meant to do. That would be:
to choose-school
if breed = workingclass
[ set targets schools with-max [ schoolachievement ] with [ expensive? = false ]
set candidates targets with [ count link-neighbors < max-link-count ]
if any? candidates
[ create-link-with one-of candidates
set enrolled? TRUE
]
]
end
Note that I also changed to targets instead of target, which is one way to keep track of whether something is an agent or an agentset.
The other way you could do this and keep it as an agent is:
to choose-school
if breed = workingclass [
set target one-of schools with-max [ schoolachievement ] with [ expensive? = false ] ]
if target != nobody and [count link-neighbors] of target < max-link-count [
create-link-with target ]
set enrolled? TRUE
end
So you can use nobody instead of any? but you can't also use with in that line because the with is really a filter on a set.
I also think you have a bracketing issue - I assume you want set enrolled? TRUE inside the brackets. I left it in the second fix, but changed in the first error (as well as changing bracket position convention to make the code block structure more visible)

Connect turtles who are within a certain radius

I use the nw extension in NetLogo to create a network.
My aim is the following:
Check if any turtles are close by
If any turtles are close by (I tried with next 3 patches, but that might change), connect to them + there is an upper limit of possible links
I tried (and, I think, succeeded) to implement the approach, described here. Which means that the upper limit works. However, I am not able to only link to the turtles close by. I also need something to catch the error if no turtle is close by. I tried to use the in-radius command but for some reasons, it doesn't do what I want.
extensions [nw]
breed [ AT1s AT1]
turtles-own [ friends ]
to setup
ca
create-AT1s 20 [
setxy random-xcor random-ycor
set friends 3
set color green
get-radius-friends friends AT1s
]
end
to get-radius-friends [ x AgentT]
let lonely AgentT with [count my-links < x]
let candidates other AgentT with [ any? AgentT in-radius 3 AND count my-links < x ]
let new-links x - count my-links
if new-links > 0 AND any? AgentT in-radius 3
[ let chosen n-of min (list new-links count other candidates) other candidates
create-links-with chosen [ hide-link ]
set candidates other candidates
ask chosen [ if my-links = x [ set candidates other candidates ] ]
]
end
I also found the neighbors and the distance commands but these only consider the immediate surroundings which isn't what I need.
Actually, that's not the best question to pull from if you want to spatially restrict the turtles. And there's a serious problem with having the connection within the turtle creation block because there are no potential friends for the turtles created first. Unless you have a very large number of turtles, you probably don't need to worry about efficiency.
I also think the variable 'x' is unnecessary because you have the variable 'friends' available (which appears to be the number of links you want the turtle to have). And there is a new reporter up-to-n-of which makes the whole list and min unnecessary.
I think this does what you want. You may want to test is without the hide-link so you can see what it does.
breed [ AT1s AT1]
turtles-own [ friends ]
to setup
clear-all
create-AT1s 100
[ setxy random-xcor random-ycor
set friends 3
set color green
]
get-radius-friends 10 AT1s
end
to get-radius-friends [ #radius #breed ]
let linkers turtles with [breed = #breed ]
ask linkers
[ let new-links friends - count my-links
if new-links > 0
[ let candidates other linkers with [ count my-links < friends ] in-radius #radius
let chosen up-to-n-of new-links candidates
create-links-with chosen [ hide-link ]
]
]
end

Selecting an item from a list in Netlogo

I'd need to pick an object in a bag containing 20 elements with attributes c (color) and s (size). Both color and size are numbers (e.g. c= {red = 256, black = 0, ... } = {256, 0, ...}).
As in Python I'd use random.choice in numpy library, I found on the web that the corresponding function in Netlogo is the extension rnd.
Struggling along a possible solution, I did
Edited:
breed[people person]
people-own
[
ball
size
color
bag
]
to setup
create-people 5
[ set color gray
setxy random-xcor random-ycor
]
ask people[
set bag [ ] ; 0 items
]
end
To create the balls:
to create-balls
set color random 300 ; color
set size random-float 5 ; size
let this-ball self
ask one-of people [ ; ask one of people to put the ball created into the bag
set bag fput this-ball bag ; add ball to the bag
]
end
The code below should include the part of drawing:
to draw
ask one-of people [
rnd:weighted-one-of bag [ ] ; I do not know what I'd write in the brackets
]
end
As you can easily see, I've many doubts about how to implement the code.
How can I select one item from the bag depending on its size (or color)?
Can you please help me out with it?
Here is a complete model that creates people and balls as turtle agents and has 30 of the balls get chosen weighted by their size. It then opens an inspect window for the person who has chosen the most balls.
extensions [rnd]
breed [people person]
people-own [ my-balls ]
breed [balls ball]
balls-own [ chosen? ]
to setup
clear-all
create-people 20
[ setxy random-xcor random-ycor
set my-balls (turtle-set nobody)
]
create-balls 50
[ hide-turtle
set size one-of [1 2 3 4 5]
set color one-of [red white blue yellow]
set chosen? false
]
repeat 30 [draw-ball]
inspect max-one-of people [count my-balls]
end
to draw-ball
ask one-of people
[ let bag-of-balls balls with [not chosen?]
let choice rnd:weighted-one-of bag-of-balls [size]
ask choice [set chosen? true]
set my-balls (turtle-set my-balls choice)
]
end
Some things to notice:
There are NO lists in this code. There are situations where you should use lists. Common uses include memory where the order is important (eg you only want to keep track of the last 5 other people seen) or where the same agent can appear multiple times. And the list commands are very powerful. However, unless you need a list then you should use agentsets.
Each person has their own bag called 'my-balls' that contains the balls they select. That is initialised as a turtle-list as part of the setup.
I used a variable called 'chosen?' that is owned by each ball to track whether it is still in the bag for the next person to choose. Then the bag-of-balls is created only as all the balls not yet chosen.
The code for weighted random choice (when choosing from agentsets) simply has the name of the variable holding the weight as the reporter, but you could use some function such as rnd:weighted-one-of bag-of-balls [size ^ 2] if you wanted a more complicated weighting scheme.

How does one report the distance between links and use those values reported for other calculations in code?

I'm trying to calculate and report the distance (link-length) between specific agentsets in NetLogo? Is there a way to calculate link length into a list?
The movement of the agents is based on whether the distance(connection) value is below/above a threshold. However, I'm having difficulty setting the values of the link length to variable connection. (preferably in a list). I'd appreciate any help.
globals[hourly-wage connection]
breed[offices office]
breed[employees employee]
offices-own [
pay-high ;; 7 offices pay well
pay-low ;; 3 offices dont pay well
]
to setup
clear-all
create-offices 10 [
set size 1.0
set color blue
set shape "house"
setxy random-xcor random-ycor
ask offices [create-link-with one-of other offices] ;; undirected links
ask links [set color red]
]
create-employees 2 [
set size 1
set color brown
set shape "person"
]
set hourly-wage 20
end
;;;;
to go
cal-dist
ask employees [
if connection > 15
move-to one-of high-pay office
if connection <= 15
move-to one-of low-pay office
]
end
to cal-dist
set connection [list print link-length] ;;
ask links [show link-length]
set salary (hourly-wage * connection) ;;; salary printed in a list
end
Not exactly sure what you're trying to do here with connection etc, but you can put any link variables into a list using of- for example:
to setup
ca
; First create the agents
crt 5 [
while [ any? other turtles in-radius 5 ] [
move-to one-of neighbors
]
set color blue
set shape "house"
]
; Once they're created, have them link with
; one of the other agents
ask turtles [
create-link-with one-of other turtles [
set color red
]
]
let link-lengths [ link-length ] of links
print link-lengths
reset-ticks
end
I don't know that this actually answers your question, so you may want to provide more detail as to what you're trying to accomplish with these links.

Making undirected links from an agent to an agentset

I am trying to create links from agents (in my case, towers) with a certain property to other towers with another set of properties. Only some of them should be linked, yet when I ask the observer, it says they all seem to have that link.
to setup-links
print count towers with [ any? tower-communications ]
ask towers with [ heading = 0 ] [ ; first consider the communications between different areas
create-tower-communications-with other towers with [ heading = 0 ] ; between two towers that are still standing
in-radius tower-communication-radius ; and link towers to each other if they are close enough
with [ heading = 0 ]
[set color green]
end
print count( tower-communications with [ color = green ])
print count( towers with [ any? tower-communications ])
The first print statement gives as expected, the number of links between these pairs. The second should print out the number of towers that have a link between them, but it gives me the full number of towers in the system instead. What is going wrong? I only want the set of agents that have tower-communications with at least one other agent.
I think the problem is the way you are counting the turtles with links, not the way you are creating the links. Here is a full example (note that I took out the second with [heading = 0].
globals [tower-communication-radius]
to setup
clear-all
create-turtles 25
[ setxy random-xcor random-ycor
set heading 0
]
set tower-communication-radius 5
setup-links
end
to setup-links
print count turtles with [ any? links ]
ask turtles with [ heading = 0 ]
[ create-links-with other turtles with [ heading = 0 ]
in-radius tower-communication-radius
[set color green]
]
print count turtles
print count turtles with [ any? links ]
print count turtles with [ any? my-links ]
end
Your count is print count turtles with [ any? links ]. However, the test you are asking is whether there are any links in the model, not whether there are any links attached to the turtle (or tower). You need my-links or link-neighbors to apply to the specific turtle.