Determining the Inter-cluster distance using dbscan in netlogo - netlogo

How will you about finding the average inter-cluster distance using dbscan in netlog assuming you have the following code (courtesy of #Nicolas-Payette):
extensions [ dbscan ]
to setup
clear-all
ask patches [ set pcolor white ]
create-turtles 1000 [
set color black
set label-color blue
setxy random-xcor random-ycor
]
ask n-of 5 turtles [
ask turtles in-radius 3 [
set color one-of [red grey]
]
]
end
to find-clusters
let red-grey-turtles turtles with [ member? color [red grey] ]
let clusters dbscan:cluster-by-location red-grey-turtles 3 3
(foreach clusters range length clusters [ [c i] ->
foreach c [ t ->
ask t [ set label i ]
]
])
end
Let us take a the endpoints of the distances being measured to be the centers of the clusters of turtles.

This depends on how you define inter-cluster distance. There are a number of ways to do it.
Let us take a the endpoints of the distances being measured to be the centers of the clusters of turtles.
While this is a good technique for, say, K-means clustering, it doesn't work as well for DBSCAN as the clusters can be concave. Thus, the center may be outside of the cluster! Regardless, I'll include as an option.
First, let's define our distance measure:
Mean distance between points in clusters:
to-report cluster-distance [ cluster1 cluster2 ]
report mean [ mean [ distance myself ] of cluster2 ] of cluster1
end
Minimum distance between points in clusters:
to-report cluster-distance [ cluster1 cluster2 ]
report min [ min [ distance myself ] of cluster2 ] of cluster1
end
Distance between centroids
Assuming world wrapping is off:
to-report cluster-distance [ cluster1 cluster2 ]
let x1 mean [ xcor ] of cluster1
let y1 mean [ ycor ] of cluster1
let x2 mean [ xcor ] of cluster2
let y2 mean [ ycor ] of cluster2
report sqrt ((x1 - x2) ^ 2 + (y1 - y2) ^ 2)
end
If world wrapping is on
; This is super complicated because, with wrapping on, xcor and ycor are
; more like angles rather than cartesian coordinates. So, this converts
; them to angles, gets the mean of those angles, and converts them back.
; Related SO question: https://stackoverflow.com/questions/24786908/get-mean-heading-of-neighboring-turtles
to-report xcor-mean [ xcors ]
let angles map [ x -> 360 * (x - (min-pxcor - 0.5)) / world-width ] xcors
let mean-x mean map cos angles
let mean-y mean map sin angles
report (atan mean-y mean-x) / 360 * world-width + (min-pxcor - 0.5)
end
to-report ycor-mean [ ycors ]
let angles map [ y -> 360 * (y - (min-pycor - 0.5)) / world-height ] ycors
let mean-x mean map cos angles
let mean-y mean map sin angles
report (atan mean-y mean-x) / 360 * world-height + (min-pycor - 0.5)
end
to-report cluster-distance [ cluster1 cluster2 ]
let x1 xcor-mean [ xcor ] of cluster1
let y1 ycor-mean [ ycor ] of cluster1
let x2 xcor-mean [ xcor ] of cluster2
let y2 ycor-mean [ ycor ] of cluster2
report sqrt ((x1 - x2) ^ 2 + (y1 - y2) ^ 2)
end
Averaging the distances
Once we have a distance measure, getting the average distance is relatively simple using map. Note that the remove below is necessary as we don't want to include a cluster's distance to itself in the mean. Note also that this code is a little inefficient in that it calculates all distances twice, but that also greatly simplifies it:
...
; This line is modified so that we get a list of turtle sets rather than
; a list of lists.
let clusters map turtle-set dbscan:cluster-by-location red-grey-turtles 3 3
let avg-distance mean map [ c1 ->
mean map [ c2 ->
cluster-distance c1 c2
] remove c1 clusters ; Get distance to all other clusters but c1
] clusters

Related

How to visualize two (or more) subnetworks in Netlogo using circle layout

I would like to know if it could be possible to visualize two distinct subnetworks (e.g., made up by turtles white and another one made up by turtles orange) with some links between them.
Visually, they should look like two networks having layout circle (layout-circle), for instance.
Currently I can visualize only one network made up by turtles orange and white (to give you an idea: https://www.dreamstime.com/royalty-free-stock-photos-people-join-merge-social-two-circles-as-network-business-groups-image30895498).
Any help would be great.
Thanks.
An example of what I am trying to do is shown below.
to WS [N k p]
create-types1 N [
set color white
setxy random-xcor random-ycor
]
create-types2 N [
set color orange
setxy random-xcor random-ycor
]
layout-circle sort types1 max-pycor * 0.9
let lis (n-values (k / 2) [ [i] -> i + 1 ])
ask types1 [
let w who
foreach lis [ [i] -> create-link-with (type1 ((w + i) mod N)) ]
]
rewire p
end
to rewire [p]
ask links [
let rewired? false
if (random-float 1) < p
[
let node1 end1
if [ count link-neighbors ] of node1 < (count types1 - 1)
[
let node2 one-of types1 with [ (self != node1) and (not link-neighbor? node1) ]
ask node1 [ create-link-with node2 [ set rewired? true ] ]
]
]
if (rewired?)
[
die
]
]
end
The code above should create a small world network where there are two types of breeds: type1 and type2, distinguished by the color.
Instead of visualizing the types within the same network, I would like to create one small world network for type1 and another one for type2. These two networks would be linked by a few links that there might exist between the two types.
Are you looking for something along these lines?
I create both circles independently and then move them to their desired position, as well as creating the links separately for both types.
breed [types1 type1]
breed [types2 type2]
to WS [N k p]
create-types1 N [
set color white
]
create-types2 N [
set color orange
]
layout-circle sort types1 max-pycor * 0.5
ask types1 [setxy xcor - 5.5 ycor]
layout-circle sort types2 max-pycor * 0.5
ask types2 [setxy xcor + 5.5 ycor]
let lis (n-values (k / 2) [ [i] -> i + 1 ])
ask types1 [
let w who
foreach lis [ [i] -> create-link-with (type1 ((w + i) mod N)) ]
]
;let links1 link-set [my-links] of types1
ask types2 [
let w who
foreach lis [ [i] -> create-link-with (type2 ((w + i) mod N + N)) ]
]
;let links2 link-set [my-links] of types2
end

NetLogo nw extension: how to use nw:extension for multiple destination

Hi guys is it possible for netlogo nw:extension to calculate path for multiple destination.
I wanted my source 0 to pass by all the red nodes destination.
I've attempt by first putting the node-links of to all destination is a list. Then from there i take the minimum number of node-links as my first path and then put the nodes(turtle) and node-link to visited so it doesn't check the node and it's link again. Eg (node-link 0 4) (node-link 0 8), then add the links and the destination node 8 to visited. I do not know how to check that the node 8 is selected.
Any idea??
to setup
ca
crt Nodes
set-default-shape turtles "circle"
let positions [
[-7 7] [-1 7] [5 7] [11 7] [-7 1] [-1 1] [5 1] [11 1] [-7 -5] [-1 -5] [5 -5] [11 -5]
[-7 -11] [-1 -11] [5 -11] [11 -11]
]
foreach sort turtles [
nodePos -> ask nodePos [
setxy (first first positions) (last first positions)
set positions but-first positions
]
]
ask turtles [;setxy random-xcor random-ycor
if Show_Names? = True [show-names]]
;ask patches [set pcolor white]
end
to create-random-graph
ask links [die]
ask turtles [
set color blue
let neighbor-nodes other turtles in-radius 6
create-node-links-with neighbor-nodes [
set weight 1
set label weight
set color grey
set thickness 0.1
]
]
to TEST
let FDestin[ 9 6 8]
let Origin 0
let a 0
let b []
let i 0
while [a < length(FDestin) ][
let Destin item a FDestin
ask turtle Origin [
set path nw:weighted-path-to turtle Destin weight
set b lput(path ) b
]
set a a + 1
]
let findMinPath sort-by [ [list1 list2] -> length(list1) < length (list2) ]b
let findMin []
set findMin lput item 0 findMinPath findMin
;foreach findMin [ x -> ask one-of node-links x [die]]
end
This is sort of rough but may get you started. With these extensions and setup:
extensions [ nw ]
undirected-link-breed [ node-links node-link ]
breed [ nodes node ]
breed [ walkers walker ]
turtles-own [ path target-nodes ]
links-own [ weight ]
to setup
ca
set-default-shape nodes "circle"
set-default-shape walkers "arrow"
let vals ( range 11 -11 -5 )
foreach vals [ y ->
foreach reverse vals [ x ->
ask patch x y [
sprout-nodes 1 [
set color blue
set label who
set size 2
]
]
]
]
create-network
ask one-of nodes [
hatch-walkers 1 [
set color green
set pen-size 5
pd
set target-nodes nobody
set path []
]
ask n-of 3 other nodes [ set color red ]
]
reset-ticks
end
That creates a grid of nodes, as well as a single walker randomly placed on one of the nodes. Three of the nodes without a walker are red to act as 'target' nodes in the path. Then, your network procedure as in your question:
to create-network
ask links [die]
ask nodes [
set color blue
let neighbor-nodes other turtles in-radius 5
create-node-links-with neighbor-nodes [
set weight one-of [ 1 2 3 ]
set label weight
set color grey
set thickness 0.1
]
]
end
That gives you a randomly weighted network of links for the walker to follow.
Now, to build paths, get the walkers to recognize the red nodes as possible targets. Then, generate all possible path permutations, always starting at the node that the walker is on.
Permutations are generated using code modified from this answer
to-report path-permutations [ node-list ] ;Return all permutations of `lst`
let n length node-list
if (n = 0) [report node-list]
if (n = 1) [report (list node-list)]
if (n = 2) [report (list node-list reverse node-list)]
let result []
let idxs range n
foreach idxs [? ->
let xi item ? node-list
foreach (path-permutations remove-item ? node-list) [?? ->
set result lput (fput xi ??) result
]
]
report result
end
Edit: instead of fewest turtles en route, turtles now select the route with the smallest weighted distance.
Count the number of turtles of each possible path, and select the path with the smallest weighted distance over the entire route.
to set-path
if target-nodes = nobody [
; Designate any red nodes as targets
set target-nodes nodes with [ color = red ]
let start-node one-of nodes-here
; Get a list of nodes
let target-node-list sort target-nodes
; Build all possible paths
let possible-paths map [ i -> sentence start-node i ] path-permutations target-node-list
; Get the weighted distance turtles for each possible path
let path-turtles map [ i -> turtles-on-path i ] possible-paths
; Keep the path with the smallest overall weighted distance
let shortest-path reduce [
[ shortest next ] ->
ifelse-value ( weighted-dist-of-path shortest < weighted-dist-of-path next ) [ shortest ] [ next ] ] path-turtles
set path shortest-path
]
end
set-path uses these two reporters:
to-report turtles-on-path [ in-path ]
; A reporter that returns the path from the start node of a given path
; to the final node of that path.
let temp-path []
( foreach ( but-last in-path ) ( but-first in-path ) [
[ from to_ ] ->
ask from [
ifelse length temp-path = 0 [
set temp-path nw:turtles-on-weighted-path-to to_ weight
] [
set temp-path sentence temp-path but-first nw:turtles-on-weighted-path-to to_ weight
]
]
] )
report temp-path
end
to-report weighted-dist-of-path [ in-path ]
let weighted-dist 0
( foreach ( but-last in-path ) ( but-first in-path ) [
[ f t ] ->
ask f [
set weighted-dist weighted-dist + nw:weighted-distance-to t weight
]
] )
report weighted-dist
end
Once the turtle knows what path it should take, it can follow that path somehow- here is a simple example.
to follow-path
if length path > 0 [
let target first path
face target
ifelse distance target > 0.5 [
fd 0.5
] [
move-to target
ask target [
set color yellow
]
set path but-first path
]
]
end
All that is wrapped up in go like so:
to go
if not any? nodes with [ color = red ] [
stop
]
ask walkers [
set-path
follow-path
]
tick
end
To give behavior something like:
Edit:
The much-simpler option is to just have the walker check the nearest (by weight) target node, build the path, follow that path, then select the next nearest target once it reaches the end of that path (and so on). However, that may not give the overall shortest path- for example, look at the image below:
The green trace is the path taken by the path-permutations walker. The blue square indicates the starting node, the orange squares designate the target nodes. The orange trace is the one taken by the simpler walker (as described above). You can see that overall, the path taken by the simpler walker has a higher overall weight cost because it is only assessing the weighted path to the next target rather than the overall weighted cost of the entire path.

How to distribute turtles similar to a population distributed across the patches

I have a model in which a population is normally distributed across the patches. I used the following code to do that:
ask patches [
let x1 (pxcor - mean1) / sd-pop1
let y1 (pycor - mean2) / sd-pop1
set popualation ( (pop1) * exp (-0.5 * ( x1 ^ 2 + y1 ^ 2)) / (2 * pi * sd-pop1 ^ 2))
]
I want to distribute 10 turtles in a similar manner. In the attached image just as how the major chunk of the population is distributed across the patches close to the center of the grid space. Similarly of the 10 turtles to be created, i want a major chunk to be randomly spread across the population rich patches and a few which are spread on the periphery.
to setup-parties
create-parties Num-of-parties
let sp sqrt((((sd-pop1 ^ 2) * (pop1 - 1)) + ((sd-pop2 ^ 2) * (pop2 - 1))) / (pop1 + pop2 - 2))
ask parties [
ifelse (pop2 > 0) [ set heading random-float 360 jump random-float sp ] [ set heading random-float 360 jump random-float sd-pop1 ]
set size 3
set color random 130
set label who + 1
set label-color red
set my-old-size 1
set shape "default"
set old-x xcor
set old-y ycor
update-rule
]
end
I would use the rnd extension for this and select 10 patches (weighted by population) to sprout a turtle. Something like ask rnd:weighted-n-of 10 patches [ population ] [ sprout 1 ]. You will also need extensions [rnd] at the top of your code if you use this method.

Find the presence of other turtles in a given direction upto a distance

I wish to find out whether in a given turtle's heading there is another agent present upto a given distance.
Here the Distance is "D".
Note:
Any agent present before D in the given direction should be also considered.
Even the direction doesn't coincide with the other's agent centre but just touches it ,even then that agent should be considered.
Problem:
No turtle-ahead procedure available. Combination of patch-ahead and turtles-on not applicable due to patch-size>> turtle-size.
Possible approach:
1.Represent the turtle's heading by the equation of a line.
to-report calculate-line[x y angle]
let m tan angle
let A m
let B -1
let C (- m * x + y)
report (list A B C)
end
to-report heading-to-angle [ h ]
report (90 - h) mod 360
end
let line-equ calculate-line (xcor) (ycor) (heading-to-angle heading)
2.Calculate the perpendicular distance from other turtles here, Check if there are within a range that the size of other turtles.
to-report value[A X1 Y1];;A is list of coefficents of line, x1 and y1 are coordinates of red turtle
if-else(abs((item 0 A * X1 + item 1 A * Y1 + item 2 A) / (sqrt((item 0 A ^ 2) + (item 1 A ^ 2) ))) < [size] of wall )
[ report "true"][report "false"]
end
3.To check if the red turtle is within D. One could obtain a line perpendicular to black one and compute the red turtle distance from it to check if it is less than or equal to D. But then that adds more complication.(Though one can simplify rotate the turtle by 90 left or right and get the line equation.)
This is what I meant by my comment. Run this code (as its own model). What it does is turn all the turtles on a few 'ahead' patches a different colour. I know this is not what you are trying to do, but the agentset candidates is a relatively small number of turtles. These are the only ones that you have to check whether they are on the correct path. So instead of turning them a different colour you could check the direction that they are from your initial turtle.
to setup
clear-all
set-patch-size 25
resize-world -10 10 -10 10
create-turtles 1000
[ setxy random-xcor random-ycor
set color yellow
set size 0.4
]
ask one-of turtles
[ set color red
set size 1
check-from-me 5
]
end
to check-from-me [howfar]
let counter 0
let candidates turtles-here
while [counter < howfar]
[ set counter counter + 1
set candidates (turtle-set candidates turtles-on patch-ahead counter)
]
ask candidates [set color red]
end
to-report check-wall
let return false
hatch 1[
set color black
set size ([size] of one-of walls) / 2
show (2.5 * ([size] of myself))
while [distance myself < (2.5 * ([size] of myself))]
[
fd ([size] of one-of walls) / 64
if any? walls in-radius size
[
set return true
]
show distance myself
]
]
report return
end
The above works. But still is approx. I am looking for better solution with probably less maths as one elucidated in the question.

Normal distribution for turtle at start

I want to randomly place turtles within some x and y coordinates confines according to a Gaussian Distribution with no two turtles at the same patch.
Things I have tried:
1. There exists http://ccl.northwestern.edu/netlogo/docs/dictionary.html#random-normal
but there how do I avoid turtles getting located same patch.
Previous code I used(only randomly distributed):
ask n-of population patches-in-box
[
sprout-inboxturtles 1
]
;population- number of turtles
;patches-in-box -where i want to place turtles
I just realized that you can get around the speed problem completely by using the rnd:weighted-n-of primitive of the NetLogo Rnd Extension! Here is some revised code:
extensions [ rnd ]
to distribute-turtles [ pop box ]
if pop > count box [ error "Box can't hold all turtles!" ]
let ys [ pycor ] of box
let xs [ pxcor ] of box
let min-x min xs
let min-y min ys
let max-x max xs
let max-y max ys
let mid-x mean list min-x max-x
let mid-y mean list min-y max-y
let w max-x - min-x
let h max-y - min-y
ask rnd:weighted-n-of pop box [
[ (p (pxcor - mid-x) (w / 6)) * (p (pycor - mid-y) (h / 6)) ] of ?
] [ sprout 1 ]
end
to-report p [ x std-dev ]
report (1 / (std-dev * sqrt (2 * pi))) * e ^ (0 - ((x ^ 2) / (2 * (std-dev ^ 2))))
end
What rnd:weighted-n-of does is that it takes an agentset (or a list) and a reporter task that should return a "weight" for each element. Elements with greater weights have better chances of being picked. In our case, we assign these weights to patches in the box using the probability density function of a normal distribution (that's the p reporter in the code).
You can use distribute-turtles in the same way as in my other answer:
to setup
ca
let patches-in-box patches with [ abs pxcor < 10 and abs pycor < 10 ]
let population (count patches-in-box - 10)
ask patches-in-box [ set pcolor black + 2 ]
distribute-turtles population patches-in-box
end
...but in this case, the code runs very fast even if population is almost as big as count patches-in-box. Why? Because rnd:weighted-n-of is "smart" enough to sometimes discard the elements that have already been picked and keep picking amongst only the ones that haven't been picked yet. (You can look at the underlying Scala code if you are interested in the details.) In our case, it means that patches near the center of the box won't get unsuccessfully picked over and over again: only the free spots will remain in play towards the end.
There is no built-in equivalent of n-of for normal distributions (and it's not clear to me what it should be if there was one). So you'll have to use random-normal and adapt it to your special case:
to distribute-turtles [ pop box ]
if pop > count box [ error "Box can't hold all turtles!" ]
let ys [ pycor ] of box
let xs [ pxcor ] of box
let min-x min xs
let min-y min ys
let max-x max xs
let max-y max ys
let mid-x mean list min-x max-x
let mid-y mean list min-y max-y
let w max-x - min-x
let h max-y - min-y
crt pop [
loop [
let x random-normal mid-x (w / 6)
if x > max-x [ set x max-x ]
if x < min-x [ set x min-x ]
set xcor x
let y random-normal mid-y (h / 6)
if y > max-y [ set y max-y ]
if y < min-y [ set y min-y ]
set ycor y
if not any? other turtles-here [ stop ]
]
move-to patch-here ; to center in patch
]
end
And this is an example of how you would call it:
to setup
ca
let population 100
let patches-in-box patches with [ abs pxcor < 10 and abs pycor < 10 ]
ask patches-in-box [ set pcolor black + 2 ]
distribute-turtles population patches-in-box
end
A few notes:
The code would be more efficient if you passed it min-x, max-x, min-y and max-y directly instead of figuring out these values from the box agentset, but it should not make a huge difference unless your box is really big.
We need to make sure that pop is less than the number of the patches, or it would loop forever because there would not be any free patch where to put the turtles: this is why we throw an error when it happens. And the closer pop is to count box, even if it gives no error, the longer it will take to complete because the last few turtles will have a hard time finding a spot.
You can play with the standard deviations (w / 6 and h / 6) to get the distribution shape you want (that's basically the "steepness" of the bell curve).
random-normal is theoretically unbounded, so it could give you coordinates that are outside the box. This is why we "clip" the results to the min and max possible coordinates. If your standard deviations are too high, you may find that a lot of turtles end up "stuck" on the borders of the box.