I created a small undirected network, where some nodes are as sources and some are targets. then I created walkers placed on source nodes.
Now, I want to implement a very simple local routing algorithm using this network.
Here, my algo steps;
1 go
2 get-list-of-neighbors
3 select one-of from list of neighbors
check is-visited:
if yes: [remove from the list
check is-loop
if yes: Die
else go to setp 3]
4 else Move-to selected node
5 check is-target?
if yes: die
else add to list-of-visited and Go
Question:
I'm new to Netlog, and don't know how to implement this algorithm.
Here is my code.
to go
ask walkers[
set list-of-neighbors (list [link-neighbors] of location)
let selected-node one-of list-of-neighbors
if (visited?=true)[ set list-of-neighbors remove-duplicate list-of-neighbors
chek if loop? exist
if yes:
if no:
if(visited?=false)[ move-to selected-node]
set location selected-node
ask location[ ifelse target=true[die][set list-of-visited lput location
go ]
end
My answer here is a slight modification to my answer to your other question. I'm not sure exactly what you mean by check is-loop, so in my solution I just have the walkers die if they have no neighboring nodes to which they can move (as they have already visited that node). Additionally, I'm suggesting a slightly different approach to accomplish the same idea as the algorithm you outline. The steps here are more like:
Walker selects one of the neighbors to which it has not already moved
If no such neighbor exists (as it has already visited all neighbors of its current location) the walker dies.
If a neighbor that has not been visited does exist, the walker will move to that neighbor, and add its new location to its variable locations-list
If the new location is a target:
Target node is marked as visited
Target node changes its color
The walker dies
If no walkers remain at the end of the go procedure, a new walker is spawned on the source node.
If all targets are visited, the model stops
Obviously if there is a linear path with multiple target nodes on it, the walkers will die each time they come to the first target and so will never visit those nodes that are farther along- but this is just an example. Remove the die chunk or modify other things to play around.
Like I said, this is only a very small modification to the answer linked above, but I copy the whole code below for easy access.
breed [nodes node]
breed [walkers walker]
walkers-own [location locations-list]
nodes-own [ source? target? visited? ]
to setup
clear-all
set-default-shape nodes "circle"
create-nodes 30 [
set color blue
set target? false
set source? false
set visited? false
]
ask nodes [ create-link-with one-of other nodes ]
repeat 500 [ layout ]
ask nodes [
setxy 0.95 * xcor 0.95 * ycor
]
ask n-of 3 nodes [
set target? true
set color white
]
ask n-of 1 nodes with [ target? = false ] [
set source? true
set color green
]
spawn-walkers
reset-ticks
end
to layout
layout-spring nodes links 0.5 2 1
end
to spawn-walkers
create-walkers 1 [
set color red
set location one-of nodes with [ source? ]
move-to location
set locations-list ( list location)
]
end
to go
ask links [ set thickness 0 ]
ask walkers [
let new-location one-of ( [link-neighbors] of location ) with [ not member? self [locations-list] of myself ]
ifelse new-location = nobody [
print "I'm stuck!"
die
]
[
move-to new-location
set location new-location
set locations-list lput location locations-list
ask location [
set visited? true
if target? = true [
set color color + 1
ask myself [
die
]
]
]
]
]
if not any? nodes with [ target? = true and visited? = false ] [
print ("All target nodes have been visited.")
stop
]
if count walkers < 1 [
spawn-walkers
]
tick
end
My Question/ algorithm Description:
Walker Start from Source node
At each node, each walker chooses the next node of its neighbor's
If all the neighboring nodes have not been visited, then the next neighbor is chosen among the nodes that have not been visited
If all the neighboring nodes have been visited previously, then the next node is chosen uniformly among all the neighbors. The walker is forced to return to a previously visited node
If a cycle is detected, that is, the walker has to die
If all targets are visited, the model stops
Related
I’m creating a model in which turtles choose and traverse a least cost path in a network environment, one node at a time.
I’m using the nw:turtles-on-weighted-path-to primitive from the NW extension to let my turtles choose a path. Relevant snippets of my code (which so far works fine) are below:
undirected-link-breed [ routes route ]
undirected-link-breed [ tracts tract ]
breed [ stalkers stalker ]
stalkers-own [ energy ]
links-own [ difficulty ]
to setup-network
ask routes [
set thickness 2
set color white
set difficulty 1
]
ask tracts [
set thickness 2
set color black
set difficulty 2
]
end
to enter-the-zone
ask stalkers [
let path nobody
let target one-of nodes-on patch -10 42
ask nodes-on patch-here [ set path but-first nw:turtles-on-weighted-path-to one-of nodes-on patch -10 42 difficulty ]
ifelse patch-here != ( patch -10 42 )
[
face first path
move-to first path
]
[ return_to_base
]
]
tick
end
to return_to_base
move-to patch -258 -231
end
However, I would like to add an “energy” attribute to my turtles that depletes a little every time they reach a new node. The catch is: I would like this loss of energy to be equal to the difficulty of the link between the node they are now and the node in which they just were.
What would be the best way to implement that?
Thanks in advance for the help.
I am creating a simulation which copies shoplifter behaviour. Turtles are split between "professional" and "novice" shoplifters and if "professionals" are apprehended by store security they might (1/2) want to select a new store to target "new-store-required".
"professional" shoplifters target the store with the lowest "security" value in a certain radius, all values are set as they are created.
I am trying to set a new "target-store", a "store" in-radius 10 with the second lowest "security", i.e. excluding the current "target-store" but I am having difficulty.
So far I have attempted to made several additions to the following code to exclude the current target store, this includes variations of "member? my patches" as the "store" where the shoplifter has been apprehended is added to this "patch-set" which will inform a later command. Also I have made a list of ascending "security" values to tell the "shoplifter" to target the "store" with "security" (the value which determines store vulnerability) the same as item 1 on the list, but I fear this might not work because their original target-store might not necessarily be item 0 as they target the store with the lowest "security" in a 10 unit radius.
These are the lines of code I am working with at the moment, any suggestions would be greatly appreciated.
***Edit: I could ideally like the code to make use of "mypatches" so each time a professional shoplifter is apprehended at a store that store can be added to mypatches and the subsequent target-store can exclude all stores which are members of mypatches.
to new-target-store
ask turtles [ if
new-store-required = 1 and professional = 1 and (random-float 1 < 0.5) [
set target-store min-one-of store in-radius 10 [security]
]
]
end
Edit 2: I've fixed what was wrong.
You may want to include your setup code, or a stripped-down version of it if it's really long, to make sure that answers conform to the structure you've used. I would approach this by having a turtles-own variable to store their current target, which they can try to fill if it is empty (rather than using an extra boolean for that purpose). Also, you may want to convert your 1/0 options to true/false for cleaner code. Check out this example setup:
globals [ stores ]
patches-own [ security ]
turtles-own [
current-target
professional?
mypatches
]
to setup
ca
ask n-of 20 patches [
set pcolor green
set security 1 + random 10
]
set stores patches with [ pcolor = green ]
crt 5 [
setxy random-xcor random-ycor
pd
set professional? one-of [ true false ]
set current-target nobody
set mypatches ( patch-set )
]
reset-ticks
end
This sets up a world with some green patches that are grouped into the patch-set called stores. Also, you have some turtles that have the boolean professional? set to either true or false. They initialize with no current-target store, and an empty mypatches patch-set variable.
Now, you can have turtles check if their current-target exists. If it does not, they can assign a store to that variable from the set of stores (possible-targets, here) that are not equal to the patch-here of the asking turtle. Professional thieves can further refine possible-targets to exclude any stores at which they have been apprehended, by excluding any stores that are a member of their mypatches patch-set variable. More details in comments:
to go
ask turtles [
; if you have no target currently
if current-target = nobody [
; Create a temporary patch set made up of all stores except for
; the one that I'm currently in
let possible-targets stores with [ self != [patch-here] of myself ]
ifelse professional? [
; Have professional thieves revise their possible targets to exclude
; any in the patchset mypatches, then choose a possible target
set possible-targets possible-targets with [ not member? self [mypatches] of myself ]
set current-target min-one-of possible-targets in-radius 10 [ security ]
] [
; Have amateur thieves choose randomly from the possible targets
set current-target one-of possible-targets
]
]
; move closer to your current target, or
; move to it exactly if you're near enough
ifelse current-target != nobody [
face current-target
ifelse distance current-target > 1 [
fd 1
] [
move-to current-target
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; *** do your shoplifting attempt/check here ***
; For this example, just have professional thieves sometimes
; add this patch to their mypatches patchset
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
if professional? and random-float 1 < 0.5 [
set mypatches ( patch-set mypatches patch-here )
]
; Reset current-target to nobody
set current-target nobody
]
] [
; if no suitable nearby targets, wander randomly
rt random 61 - 30
fd 1
]
]
tick
end
If you run that long enough, eventually your professional thieves will stop being able to find target stores as they have added all stores to their mypatches variable.
i want my variable to inherit the label of my turtles.
im making routes for them and want them to remember the last place they visited.
so theyll continue to the next place in the chain.
ifelse last_place = home
[set place min-one-of (turtles with [label = "mall"])[distancemyself]]
[set place min-one-of (turtles with [label = "home"])[distancemyself]]
i cant use my actual code in here but hopefully, you get the gist
if
place = one-of turtles with [label = "mallI]
I want to add
set last_place label of place
i want last_place to get the label of place.
i know it can create loops if i have the same place twice in the same route but i want to create a list to prevent them but right now i need a sort of where flag that will make my turtles keep going to the end.
Hard to say without seeing more of your code- it's hard to know what turtle is doing what. If your code is sensitive, I'd recommend following the tips in the MCVE guidelines to make a reproducible example- it might be easier to address your exact problem that way!
As an alternative, instead of using a label it's probably better to just have the turtles store the "location" turtle or patch in a turtle-variable. Using this simple example setup:
breed [ walkers walker ]
breed [ locations location ]
walkers-own [ location-list ]
to setup
ca
create-walkers 10 [
setxy random-pxcor random-pycor
set location-list []
pd
]
create-locations 20 [
set size 1.5
set shape "house"
setxy random-pxcor random-pycor
]
reset-ticks
end
You can have turtles store the places they visit in a list and reference them that way.
to go
ask walkers [
; Build an agrentset of locations that do not belong
; to each turtle's 'location-list'
let unvisited-locations locations with [
not member? self [location-list] of myself
]
; Target the nearest unvisited location
let target min-one-of unvisited-locations [ distance myself ]
; if the target exists, move towards it
if target != nobody [
face target
ifelse distance target > 1 [
fd 1
] [
move-to target
set location-list lput target location-list
]
]
; if a turtle visits all locations, remove the
; first location visited from the 'location-list'
; so that it will follow the same pattern continuously
if length location-list = count locations [
set location-list but-first location-list
]
]
tick
end
I have been trying to work out how to make a turtle move from one node to another in a network based on a GIS road map. The issue is that the turtle cannot set a path using nw:turtles-on-path-to unless I remove node duplicates and nodes that are not connected (the relevant block of code I used is from someone else's model). Below is the code that works when I remove duplicates and unconnected nodes:
foreach gis:feature-list-of roads-dataset [ vector-feature ->
foreach gis:vertex-lists-of vector-feature [ vertex ->
let previous-turtle nobody
let first-turtle nobody
foreach vertex [point ->
let location gis:location-of point
if not empty? location
[
create-nodes 1
[ set myneighbours n-of 0 turtles
set xcor item 0 location
set ycor item 1 location
set road-type gis:property-value vector-feature "Classification"
;set shape "circle"
;set size 0.5
ifelse previous-turtle = nobody
[ set first-turtle self ]
[ create-link-with previous-turtle ]
set hidden? true
set previous-turtle self ]
]
]
] ]
delete-duplicates
ask nodes [ set myneighbours link-neighbors ]
delete-not-connected
ask nodes [ set myneighbours link-neighbors ]
to delete-duplicates
ask nodes [
if count nodes-here with [ description = "road" ] > 1[
ask other nodes-here with [ description = "road" ][
ask myself [create-links-with other [link-neighbors] of myself]
die]
]
]
end
to delete-not-connected
ask nodes [set test 0]
ask one-of nodes [set test 1]
repeat 500 [
ask nodes with [test = 1]
[ask myneighbours [set test 1]]]
ask nodes with [test = 0][die]
end
to go
ask person [
if destination = 0 [ create-link select-destination ]
if mypath = 0 [ select-path ]
if mypath != 0 [ move ]
]
tick
end
to create-link
create-link-with min-one-of nodes [ distance myself ]
ask links [ set hidden? true ]
end
to select-destination
set destination one-of nodes with [ road-type = "main road" ]
end
to select-path
set mypath nw:turtles-on-path-to destination
end
to move
ifelse length mypath > 0
[ move-to item 0 mypath set mypath remove-item 0 mypath ]
[ stop ]
end
This code works perfectly fine. However, the road network gets distorted after deleting duplicate and unconnected nodes - the road networks does not have the same appearance as the original one. The only way the turtle can move along the network is by keeping the code in the format above. If I exclude delete-duplicatesand delete-not-connected then mypath returns false.
I there a way I can keep the appearance of the original network and at the same allow the turtle to set a path and move along it to reach the destination? What would be the issue that does not allow the turtle to set a path unless delete-duplicatesand delete-not-connected are used?
Your support is much appreciated. Thank you.
Are you sure delete-duplicates is necessary? My guess is that the reason delete-not-connected is necessary is because, without it, select-destination can select a node that is not reachable by the turtle. I'll get to how to fix this in a moment. First, there are a few problems with your code that we should discuss.
First, you have turtles create a link between them and their current location. This is a little weird, because it's essentially saying that this turtle is a road on the road network, which doesn't make sense. Practically, this gets weird if and when you want the turtles to select new destinations. They'll still be linked with the node they started on! This would allow them "teleport" around the network. Not good! Instead, I suggest creating a turtle variable called current-location, which tracks the node that the turtle is on.
So, create-link should be turned into
to set-location
set current-location min-one-of nodes [ distance myself ]
end
move then becomes (I deleted the stop from your code because it's unnecessary):
to move
if not empty? mypath [
set current-location first mypath
move-to current-location
set mypath but-first mypath
]
end
and select-path becomes:
to select-path
set mypath [ nw:turtles-on-path-to destination ] of current-location
end
Actually, we can simplify this further. Because the turtle is keeping track of its current location, you don't need to keep track of the path yourself anymore. Instead, delete mypath and select-path and change move to:
to move
if current-location != destination [
let next-node first [ nw:turtles-on-path-to destination ] of current-location
set current-location next-node
move-to current-location
]
end
and change go to:
to go
ask person [
if destination = 0 [
set-location
select-destination
]
move
]
tick
end
Much simpler! Note that this should still be fast as nw remembers the shortest path between nodes. If you have a really big network or something, you can still keep track of the path yourself if you want, but I'd try this first.
Okay, now we're ready to fix the disconnected nodes problem without deleting anything in the network. Basically, select-destination should only choose a destination that the turtle can get to. That looks like this:
(Edit: This code is incorrect. See below)
to select-destination
set destination one-of nodes with [
road-type = "main road" and
is-number? [ nw:distance-to [current-location] of myself ] of myself
]
end
The [ nw:distance-to myself ] of myself in there will get the distance from the current-location (which is what the first myself refers to) to the potential destination (which is what the second myself refers to). nw:distance-to will return a number (the distance) if the target node is reachable from the source node; otherwise it returns false. So is-number? checks to make sure it actually gave us a number back.
Hopefully this helps solve your problem while also simplifying your code. The duplicates thing really shouldn't matter. If it does, either reply with a comment or edit your question, and I'll take a look.
Edit:
Thanks for uploading your model and data! I realized I actually messed up the select-destination procedure. It should be:
to select-destination
set destination one-of [ nodes with [
road-type = "road" and
is-number? [ nw:distance-to myself ] of myself
] ] of current-location
end
That is, the person was supposed to be querying the current-location for a reachable road. Obviously, since the person is not connected to the network, they can't get a reachable road directly.
Next, it looks like a significant problem is actually the data is extremely disconnected. The network that you're creating contains 5619 disconnected components which each only contain 3-5 nodes. So it's no wonder that the turtle can't find a destination it can reach!
I think you may be interpreting the data incorrectly. I would expect that the various the nodes created from different feature lists should be connected somehow, but you're not doing that (which is why you end up with so many disconnected components). Unfortunately, this is where we hit the limit of my knowledge; I don't know much about GIS. I remember one of my colleagues that was working on a similar project had to do something like merging vertices that were on top of each other. This would turns the network generation code into the following:
foreach gis:feature-list-of roads-dataset [ vector-feature ->
foreach gis:vertex-lists-of vector-feature [ vertex ->
let previous-turtle nobody
foreach vertex [point ->
let location gis:location-of point
if not empty? location
[
let x item 0 location
let y item 1 location
let current-node one-of (turtles-on patch x y) with [ xcor = x and ycor = y ]
if current-node = nobody [
create-nodes 1 [
setxy x y
set shape "circle"
set size 0.5
set road-type "road"
set hidden? true
set current-node self
]
]
ask current-node [
if is-turtle? previous-turtle [
create-link-with previous-turtle
]
set previous-turtle self
]
]
]
]
]
This appears to behave correctly. (I also cleaned up a few things that we're doing anything) That is, it looks to see if there's already a node at that exact location, and connects to that one if so, otherwise it creates a new node.
Here's the full updated code: https://gist.github.com/qiemem/b59f3657bea34b9aa67648760b9c7471
I also tweaked a few other things: The person now sets their location in setup, which makes sense: their location should update correctly after that. I added tick to the end of go, which all models should have. You might want to change view updates to "on ticks". Finally, I made the person choose a new location upon getting to their destination for testing. You might want to make go a forever button now; you'll the person going from place to place.
Hope that helps!
I'm new to NetLogo and am attempting to model home range selection of subsequent colonizers. The model should follow simple steps:
Individual 1 picks a home range (a subset of patches).
When individual 1 is done picking its home range, it hatches new
individual 2.
Individual 2 picks a home range, then hatches individual 3.
Individual 3 picks a home range, and so on.
I'm having trouble figuring out how to get this to work. I can get the first turtle to pick a home range. But the offspring do not. Writing the code numerous ways has only accomplished two unintended outcomes. Either endless new individuals are hatched simultaneously, before the first turtle has a home range, and the new turtles fail to pick a home range. Or, the first turtle picks its home range and hatches a new turtle, but that new turtle doesn't pick a home range. Neither outcome is what I want.
How do I set this up to run as intended, so that hatchlings pick home ranges too? Here is one simplified version of my code:
to setup-turtles
crt 1
[setxy random-xcor random-ycor]
end
to go
ask turtles [pick-homerange]
tick
end
to pick-homerange
while [food-mine < food-required] ;; if not enough food, keep picking patches for home range
[;; code to pick home range until it has enough food; this is working okay
]
[;; when enough food, stop picking home range
hatch 1 fd 20 ;; now hatch 1, move new turtle slightly away
]
end
So it is at this last part, once the home range is built, that I want a new turtle to hatch from its parent. I then want that turtle to repeat the pick-homerange procedure. How could that be coded to happen? I've tried writing this every way I can think of; nothing is working. Thanks in advance for any assistance!
One way to do this is to have each patch equal one "food value", and have turtles grow their home range until their home range supplies them with enough food. I would set this up so that patches "know" to which turtle they belong, and so that turtles know how much food they need, which patches are part of their home range, and the food supplied by their homerange. Example patch and turtle variables would then be:
patches-own [
owned_by
]
turtles-own [
food_required
my_homerange
homerange_food
]
Then, your turtles can add patches into their home range until they hit their "food_required", whatever you set that as. For simplicity, in this example I assume that turtles are territorial and so won't "share" home ranges. Further explanation of steps is commented in the code below. This is intended just to get you started- for example, it will hang if you run pick-homerange too many times.
to setup-turtles
crt 1 [
set size 1.5
setxy random-xcor random-ycor
set food_required 5 + random 5
set homerange_food 0
set my_homerange []
]
end
to pick-homerange
ask turtles [
;; Check if the current patch is owned by anyone other than myself
if ( [owned_by] of patch-here != self ) and ( [owned_by] of patch-here != nobody ) [
;; if it is owned by someone else, move to a new patch that is not owned
let target one-of patches in-radius 10 with [ owned_by = nobody ]
if target != nobody [
move-to target
]
]
;; Now add the current patch into my homerange
ask patch-here [
set owned_by myself
]
set my_homerange patches with [ owned_by = myself ]
;; calculate the number of patches currently in my homerange
set homerange_food count patches with [owned_by = myself]
;; Now grow the homerange until there are enough patches in the homerange
;; to fulfill the "food_required" variable
while [ homerange_food < food_required ] [
let expander one-of my_homerange with [ any? neighbors with [ owned_by = nobody ] ]
if expander != nobody [
ask expander [
let expand_to one-of neighbors4 with [ owned_by = nobody ]
if expand_to != nobody[
ask expand_to [
set owned_by [owned_by] of myself
]
]
]
]
;; Reassess homerange food worth
set my_homerange patches with [ owned_by = myself ]
set homerange_food count patches with [owned_by = myself]
]
ask my_homerange [
set pcolor [color] of myself - 2
]
;; Now that my homerange has been defined, I will hatch a new turtle
hatch 1 [
set color ([color] of myself + random 4 - 2)
]
]
end