I would like to create a network in Netlogo, put 3 agents on the first node of the network and make them move to a connected node.
Specifically I'd like the agents choose the node to move to based on a probability. If there is no agent on a connected node, choose it with p = 0.5, if there is an agent on the node choose it with p = 0.7. So if - for example - the starting node has two neighbouring nodes and one of them has an other agent on it, it should be chosen with a higher probability.
I've managed to create the network and move the agents randomly, but I can't figure out how to make an agent "know" if there is an other agent on a node and set the probabilities based on this condition.
breed [nodes node]
breed [walkers walker]
walkers-own [location ]
to setup
clear-all
set-default-shape nodes "circle"
create-nodes 18 [set color white]
ask nodes [ create-link-with one-of other nodes ]
layout-circle nodes 10
create-walkers 3 [
set location node 1
move-to location
]
reset-ticks
end
to go
ask walkers [
let new-location one-of [link-neighbors] of location ;; choose a new location randomly
move-to new-location
set location new-location
]
tick
end
I thought of making an occupied? variable and update it based on the position of the agents, but it would be a nodes-own variable, which I couldn't connect to the agents (walkers).
I am new to Netlogo and not aware of all the possibilities and limitations, so it is possible I am looking at this problem all wrong. I would appreciate your help.
Sielu, a couple of points.
First, creating a link will fail silently if there is already a link between those two nodes. The result is that some of your nodes will end up with only one neighbor. If that's not ok, you need to work on your link creation logic.
Second, it may not be obvious, but some nodes will end up with more than two links,
so a walker may have many different paths to choose from.
Third, a node may have more than one occupant. For example, all the other walkers might be on it.
Given all that, I'm going to assume that what you're asking for is for each walker to start looking at its linked-nodes, set some probability based on the occupancy of the target node, select a random number, and if it's below that probability move to that node and stop looking at other possible moves. If the random number is above that probability, however, then the walker should forget about that link and move on to considering the next one. If all links fail their separate tests, the walker doesn't move.
The code below implements that. It got kind of long and messy. Here's the key features.
I added a verbose? switch that turns on or off printing out details for debugging
and it asks the user whether to be verbose or not on each setup. If you hit
go once ( not forever ) you can see what got set and if its what you wanted.
I added a count-of-walkers to each node, versus a true/false occupancy? switch
I added a sequence number ( like "who" ) to each watcher to make the output
read more sensibly
the GO step makes a LIST of nodes that are link-neighbors to the node the watcher
is standing on. Then it sorts the list into the order you want to examine
them. ( I used a list because you might care what order they are looked at, and
agent sets are randomly ordered. ) I sorted them into ascending order by the
the occupancy counts, so it will first look at the unoccupied nodes, then the
occupied ones, up to the most occupied ones.
Then it goes through that list, deciding whether to move to that node or not.
Once it does decide to move, it stops looking at the list, so some of the nodes
will not even be considered for a move.
You can see the section where probabilities are set depending on the occupancy
count of the node. I used your 0.5 and 0.7 probabilities and added a 0.9
probability if there are 2 or more watchers on the target node.
The code has a lot of comments,and if you set verbose? to true, you can
examine how each watcher considers ( or doesn't) each link and makes its
decision to move or not.
The code runs and looks ok, so far as I can tell what it is you want. Ask me
questions if it's not clear what I did.
breed [nodes node]
breed [walkers walker]
walkers-own [location seqnum ] ;; seqqnum is like who but for the walkers
nodes-own[ count-of-walkers ] ;; ADDED
globals [verbose?]
to setup
clear-all
set verbose? false ;; if true, prints a lot for debugging purposes
if user-yes-or-no? "Print debugging info on each step?" [set verbose? true]
set-default-shape nodes "circle"
create-nodes 18 [set color white]
ask nodes [ create-link-with one-of other nodes ]
layout-circle nodes 10
let seq 1 ;; start of sequence numbers for walkers
create-walkers 3 [
set size 3
set color red
set location node 1
set seqnum seq set seq seq + 1 ;; assign the sequence number
move-to location
ask location [ set count-of-walkers count-of-walkers + 1 ]
]
reset-ticks
end
to go
if verbose? [print " ================================== starting the go loop"]
ask walkers [
let candidate-set [] ;; this will be an agent set of neighboring linked nodes
ask location [set candidate-set link-neighbors ] ;; ask my node to find its neighbors
;; sort the neighbors into some order and make a list of them
;; the next line sorts them into ascending order by occupancy ( lowest first )
;; we will consider a move to each one in that order
let candidate-list sort-on [count-of-walkers] candidate-set
if verbose? [
type "walker " type seqnum
type " is checking out these neighbors: " print candidate-list
]
;; Examine each neighbor and decide whether to move there based on probabilities
;; if we find a place to move we like terminate processing the list
;; otherwise, remove that candidate neighbor from the list
;; and keep doing that until the list is empty
;;
while [length candidate-list > 0 ] [ ;; while we haven't decided to move yet
;; pop the first item off the list
let candidate first candidate-list ;; pull the first item
set candidate-list but-first candidate-list ;; and remove it from the list
;; decide what probability to use for considering THIS move
let prob-of-move 0 ;; a default value
let occupant-count [ count-of-walkers ] of candidate ;; count walkers on that node
if occupant-count = 0 [ set prob-of-move 0.5 ]
if occupant-count = 1 [ set prob-of-move 0.7 ]
if occupant-count > 1 [ set prob-of-move 0.9 ]
if verbose? [
type " ... candidate " type candidate
type " has this many walkers " type [count-of-walkers] of candidate
type " so set probability of move to " print prob-of-move
]
;; make a decision to move or not based on that probability
if-else random-float 1 < prob-of-move [
if verbose? [type " ......moving to " print candidate]
;;let new-location candidate
set candidate-list [] ;; make the list empty so this WHILE loop will exit
move-to candidate ;; move the walker on the display
;; update the counts of walkers on each affected node
ask candidate [ set count-of-walkers count-of-walkers + 1 ]
ask location [ set count-of-walkers count-of-walkers - 1 ]
;; finally, tell the walker where it is now
set location candidate
]
[if verbose? [ print " ..... was not selected for a move to this node"]]
]
if verbose? [ print " ..............done with processing walkers for this tick"]
]
tick
end
Related
I'm pretty new to Arangodb and I'm trying to get the last/leaf node (I guess vertex) in a graph. So given I've the following graph:
Now I want start the traversal with 6010142. The query should return 6010625 because it is the last node that can be reached via 6010145. But how does the query looks like?
I already tried:
FOR v, e, p IN 1..5 OUTBOUND {_id: 'nodes/6010142'} GRAPH 'test' RETURN v
But it also returns 6010145. Furthermore it is limited to a maxDepth of 5 but my graph can exceed the limit. So I also need a solution that works for any depth. Hopefully anyone can help me :-)
I'm also just starting out with AQL but maybe this can help.
FOR v IN 1..5 OUTBOUND {_id: 'nodes/6010142'} GRAPH 'test' OPTIONS {uniqueVertices: 'global', bfs: true}
FILTER LENGTH(FOR vv IN OUTBOUND v GRAPH 'test' LIMIT 1 RETURN 1) == 0
RETURN v
This approach follows an older ArangoDB cook book (p. 39) for finding leaf nodes. The filter line takes the connected nodes found by the first line and does a second traversal to check if this is actually a leaf.
The OPTIONS {uniqueVertices: 'global', bfs: true} part is an optimization if you are only interested in unique leaf nodes and not all the different paths to those nodes.
Regarding maxDepth I would just use a sufficiently high number. The worst case would be the number of nodes in your graph.
(The graph you posted and your description seem to disagree about the direction of the edges. Maybe you need to use INBOUND.)
Imagine the following graph:
And this query:
MATCH(p:Person {id:1})
MATCH (p)-[:KNOWS]-(s)
CREATE (p)-[:LIVE_IN]->(:Place {name: 'Some Place'})
Now, why five LIVE_IN, Place are created even though s is not involved in the CREATE statement? is there any place in the docs that explain this behavior?
Note: this is not about MERGE vs CREATE, although MERGE can solve it.
EDIT: In response to #Tomaz answer: I have deliberately placed MATCH (p)-[:KNOWS]-(s) in the query and I know how it will behave. I am asking for found explanations. For example, is CREATE will execute for each path or row in the matched patterns regardless of the node involved in the CREATE? what if you have complex matched patterns such as, disconnected graph, Trees...etc?
Also note that the direction of relationship KNOWS (- vs ->) will effect the number of returned rows (9 vs 1), but CREATE will execute five times regardless of the direction.
Update:
I have added 3 other node Office and issued the following query:
MATCH(p:Person {id:1})
MATCH (p)-[:KNOWS]-(s)
MATCH (o:Office)
CREATE (p)-[:LOVE]->(:Place {name: 'Any Place'})
And as result: 15 LOVE Place have been created, so it seems to me that cypher performs Cartesian Product between all nodes:
p refer to 1 nodes, s refer to 5 nodes, o refer to 3 nodes => 1 * 5 * 3 = 15
But I can not confirm this form neo4j docs unfortunately.
This is because the Person with id 1 has five neighbors.
In your query you start with:
MATCH(p:Person {id:1})
This produces a single row, where it finds the node you are looking for.
The next step is:
MATCH (p)-[:KNOWS]-(s)
This statement found 5 neighbors, so your cardinality or number of rows increases to five. And then you run a create statement for each row, which in turn creates five Places. You could for example lower the cardinality back to 1 before doing the CREATE and you'll create only a single place:
MATCH(p:Person {id:1})
MATCH (p)-[:KNOWS]-(s)
// aggregation reduces cardinality to 1
WITH p, collect(s) as neighbors
CREATE (p)-[:LIVE_IN]->(:Place {name: 'Some Place'})
When doing cypher query, always have in mind the cardinality you are operating.
I am creating a supply chain simulation with NetLogo. I am putting a list of lists from NetLogo to R, which is represented by distributor ID (agents who) and sales history (sales of all previous ticks). In R I train my neural network and make predictions. When I put back the answer in the same format list of lists. I need to specify which result goes to which agent. However, I do not know how to do it in NetLogo. I assume that there should be a function to do that, but as I understand the functions are programmed with Java and I would need to assign the values inside the raw code and not in the NetLogo environment. Moreover, I think that this training and predictions occurs multiple times (for each agent) and not only once.
Variable example:
[ [0] [ 100 200 300 100 200] ]
[ [1] [ 200 300 100 100 200] ]
Where the first index is agents who index and the second is the agent's sales history.
Maybe someone could explain how NetLogo and R can be combined for computational purpose and not only statistical analysis and plotting? I assume that NetLogo is similar to parallel programming, while my style of R programming is more linear.
The last part of your question is beyond me (and may be too broad for typical Stack Overflow questions- I'm not sure you'll get a useful answer here). However, maybe this example would get you in the right direction as to what you're trying to do.
I assume you're using the [r] extension as in your previous question, so using this setup:
extensions [r]
turtles-own [ rand-num ]
to setup
ca
crt 10 [
set rand-num random 5
]
reset-ticks
end
In this example, turtles have a rand-num instead of your sales history, but the concept is the same. First, build the list of lists where first index is the turtle [who] and the second is [rand-num], then output it to r (note that I also sort the list, but that is just for clarity and not actually needed):
to go
let l_list map [ i ->
list i [rand-num] of turtle i
] ( sort [ who ] of turtles )
r:put "list1" l_list
show r:get "list1"
Next, use r:eval to do whatever you need to do to the values in r- in this example I'm just using lapply to square the rand-num value (x[[2]])- but make sure to return x:
let modified_list ( r:get "lapply(list1, function(x) { x[[2]] <- x[[2]]^2; return(x)})" )
Now, to assign the turtles the modified values, use Netlogo's foreach to iterate over the modified list and ask the turtle of index 0 (turtle item 0 x) to set its rand-num to index 1 (set rand-num item 1 x):
foreach modified_list [ x ->
ask turtle item 0 x [
set rand-num item 1 x
]
]
end
If you check the sort [rand-num] of turtles before and after running go, you should see the rand-num of each turtle is squared after go is called.
New NetLogo User and first-time poster here, with some cannibalistic turtles on my hands.
About my model:
My turtles have a bodysize (bsize), and a breed (male, female, juvenile turtles). They move around in a random fashion and encounter each other on patches. When two turtles land on the same patch, my little beasts size each other up, and depending on a probability of cannibalism (PrCan) specific to the larger turtle's breed and the body size ratio (bsize_ratio) between the two, the bigger one eats the smaller one.
I don't think this is relevant, but I have created a table (PrCanTable) of 3 lists with two keys (body size ratio, breed, and probability of cannibalism) using table:make from instructions I found on this stack overflow answer.
To continue, the bigger turtle looks up the probability of cannibalizing (PrCanT) in the table (PrCanTable), then picks a random number (random-float) and compares it to the probability (PrCanT). If the random number is less than or equal to the probability, the little turtle dies. So sad!
Unfortunately, my bloodthirsty turtles are misbehaving. I am running into a problem:
There is no agent for MYSELF to refer to.
error while fa 25 running MYSELF
called by procedure CANNIBALIZE
called by procedure GO
called by Button 'go'
NetLogo has helpfully highlighted the last instance of myself in my code...but I don't know why. I think this is a problem with my own understanding of myself vs. self. I have read as much as I can, but honestly am still stumped. Can anyone take a look at this code and let me know?
to-report get-PrCan_T [ bsize_ratio_T breed_T ]
report table:get (table:get PrCanTable bsize_ratio_T) breed_T
end
to cannibalize
if ( any? turtles-here with [bsize > [bsize] of myself])
and ( random-float 1 <= get-PrCan_T ( precision( bsize / bsize of myself ) 1 ) ( [breed] of self ) )
[die]
end
Yeah, self and myself are confusing at first, but once you get the hang of it, it's really not that hard. What you need to understand is that every piece of NetLogo code runs into a "context". That context, by default, is the observer, but some primitives can introduce a new context.
ask is the most obvious way to introduce a new context: the command block that you pass to ask (delimited by [ and ]) puts NetLogo in the context of a turtle. Inside that context, self refers to the current turtle.
But sometimes you introduce a new turtle context inside an existing turtle context! Inside that new context, self changes meaning: it now refers to the turtle from the inner context. But what if you still want to refer to the turtle from the outer context? That's what myself is for.
Assuming that cannibalize is a procedure that is run by a turtle, your use of myself in turtles-here with [bsize > [bsize] of myself] is correct: the turtle running the with block is self (which you don't need to specify) and turtle running cannibalize (the "outer" turtle) is myself. The inner context was introduced by with.
But in the second part of your if condition (everything that follow and) there is no inner context anymore: you're not inside the with block anymore. So myself is not defined anymore. There is only self.
Your code is also made harder to debug by the fact that you're trying to pack everything in the same long if condition. Try splitting it up by using multiple local variables:
to cannibalize
let bigger-turtles-here turtles-here with [ bsize > [ bsize ] of myself ]
if any? bigger-turtles-here [
let cannibal one-of bigger-turtles-here
let ratio precision ([ bsize ] of cannibal / bsize) 1
let p get-PrCan_T ratio breed
if random-float 1 <= p [ die ]
]
end
One final note: in both your version and mine, the turtle running the cannibalize procedure is the one that gets eaten! That's confusing. I would either rename the procedure to get-cannibalized or switch things around so that the turtle running the procedure is the one that does the eating. (Naming is important!)
In the models library there is this procedure in the Galton Box model. Each time it is called, it makes two recursive calls, after a hatch to the left and a hatch to the right.
to propagate ;; peg procedure
if ycor < max-pycor - 2 - 2 * number-of-rows [ die ]
set pcolor yellow
set ycor ycor - 2
hatch 1 [
set xcor xcor - 1
propagate
]
hatch 1 [
set xcor xcor + 1
propagate
]
die
end
Is there any guarantee of the order of the recursive calls to 'propagate'? For example, does the first call (xcor - 1) complete entirely before the second (xcor + 1) begins? Or does the initial call start the first, then start the second? Is there any guarantee which will finish first?
It's entirely sequential. There is no parallelism or concurrency in NetLogo.
So yeah, the first call will complete entirely before the second starts.
This is from the Galton Box model, right? You can watch the recursion happen step by step as follows: switch the model from "tick-based updates" to "continuous updates", put the speed slider at a slow setting, then press the setup button. You'll see a strict left-to-right, depth-first traversal.