Build and register a k-nearest-neighbours graph between planning units using coordinates.
This constructor does not require polygon geometry. It uses planning-unit
coordinates supplied explicitly or stored in the Problem object.
Usage
add_spatial_knn(
x,
coords = NULL,
k = 8,
name = "knn",
weight_mode = c("constant", "inverse", "inverse_sq"),
distance_eps = 1e-09
)Arguments
- x
A
Problemobject created withcreate_problem.- coords
Optional coordinates specification. This may be:
a
data.frame(id, x, y), ora numeric matrix with two columns
(x, y)aligned to the order of planning units.
If
NULL, coordinates are taken fromx$data$pu_coordsor from columnsx$data$pu$xandx$data$pu$y.- k
Integer giving the number of neighbours per planning unit. Must be at least 1 and strictly less than the number of planning units.
- name
Character string giving the key under which the relation is stored.
- weight_mode
Character string indicating how distance is converted to weight. Must be one of
"constant","inverse", or"inverse_sq".- distance_eps
Small positive numeric constant used to avoid division by zero in inverse-distance weighting.
Details
Use this function when neighbourhood should be defined by a fixed number of nearby planning units rather than by polygon topology or a fixed distance threshold.
Let \(s_i = (x_i, y_i)\) denote the coordinates of planning unit
\(i\). For each planning unit, this function identifies the k
nearest distinct planning units under Euclidean distance.
If \(d_{ij}\) denotes the Euclidean distance between units \(i\) and
\(j\), then the k-nearest-neighbours relation is constructed by adding an
edge from \(i\) to each of its k nearest neighbours.
Edge weights are then assigned according to weight_mode:
"constant": $$\omega_{ij} = 1,$$"inverse": $$\omega_{ij} = \frac{1}{\max(d_{ij}, \varepsilon)},$$"inverse_sq": $$\omega_{ij} = \frac{1}{\max(d_{ij}, \varepsilon)^2},$$
where \(\varepsilon\) = distance_eps is a small constant to avoid
division by zero.
The raw k-nearest-neighbours structure is directional by construction, but
the stored relation is registered as undirected by default through
add_spatial_relations, which collapses duplicate unordered
pairs.
If the RANN package is available, it is used for efficient nearest neighbour search. Otherwise, a full distance matrix is computed.
Examples
# Load a complete simulated planning problem.
example_data <- load_sim_multiaction()
p <- create_problem(
pu = example_data$planning_units,
features = example_data$features,
dist_features = example_data$dist_features,
cost = "cost"
)
p <- add_spatial_knn(
x = p,
k = 2,
name = "knn2",
weight_mode = "constant"
)
p$data$spatial_relations$knn2
#> internal_pu1 internal_pu2 weight pu1 pu2 distance source
#> 1 1 9 1 1 9 1 knn_constant
#> 2 1 2 1 1 2 1 knn_constant
#> 3 2 10 1 2 10 1 knn_constant
#> 5 3 11 1 3 11 1 knn_constant
#> 6 3 4 1 3 4 1 knn_constant
#> 7 4 12 1 4 12 1 knn_constant
#> 9 5 13 1 5 13 1 knn_constant
#> 10 5 6 1 5 6 1 knn_constant
#> 11 6 14 1 6 14 1 knn_constant
#> 13 7 15 1 7 15 1 knn_constant
#> 14 7 8 1 7 8 1 knn_constant
#> 15 8 16 1 8 16 1 knn_constant
#> 18 9 10 1 9 10 1 knn_constant
#> 22 11 12 1 11 12 1 knn_constant
#> 26 13 14 1 13 14 1 knn_constant
#> 30 15 16 1 15 16 1 knn_constant
#> 33 17 25 1 17 25 1 knn_constant
#> 34 17 18 1 17 18 1 knn_constant
#> 35 18 26 1 18 26 1 knn_constant
#> 37 19 27 1 19 27 1 knn_constant
#> 38 19 20 1 19 20 1 knn_constant
#> 39 20 28 1 20 28 1 knn_constant
#> 41 21 29 1 21 29 1 knn_constant
#> 42 21 22 1 21 22 1 knn_constant
#> 43 22 30 1 22 30 1 knn_constant
#> 45 23 31 1 23 31 1 knn_constant
#> 46 23 24 1 23 24 1 knn_constant
#> 47 24 32 1 24 32 1 knn_constant
#> 50 25 26 1 25 26 1 knn_constant
#> 54 27 28 1 27 28 1 knn_constant
#> 58 29 30 1 29 30 1 knn_constant
#> 62 31 32 1 31 32 1 knn_constant
#> 65 33 41 1 33 41 1 knn_constant
#> 66 33 34 1 33 34 1 knn_constant
#> 67 34 42 1 34 42 1 knn_constant
#> 69 35 43 1 35 43 1 knn_constant
#> 70 35 36 1 35 36 1 knn_constant
#> 71 36 44 1 36 44 1 knn_constant
#> 73 37 45 1 37 45 1 knn_constant
#> 74 37 38 1 37 38 1 knn_constant
#> 75 38 46 1 38 46 1 knn_constant
#> 77 39 47 1 39 47 1 knn_constant
#> 78 39 40 1 39 40 1 knn_constant
#> 79 40 48 1 40 48 1 knn_constant
#> 82 41 42 1 41 42 1 knn_constant
#> 86 43 44 1 43 44 1 knn_constant
#> 90 45 46 1 45 46 1 knn_constant
#> 94 47 48 1 47 48 1 knn_constant
#> 97 49 57 1 49 57 1 knn_constant
#> 98 49 50 1 49 50 1 knn_constant
#> 99 50 58 1 50 58 1 knn_constant
#> 101 51 59 1 51 59 1 knn_constant
#> 102 51 52 1 51 52 1 knn_constant
#> 103 52 60 1 52 60 1 knn_constant
#> 105 53 61 1 53 61 1 knn_constant
#> 106 53 54 1 53 54 1 knn_constant
#> 107 54 62 1 54 62 1 knn_constant
#> 109 55 63 1 55 63 1 knn_constant
#> 110 55 56 1 55 56 1 knn_constant
#> 111 56 64 1 56 64 1 knn_constant
#> 114 57 58 1 57 58 1 knn_constant
#> 118 59 60 1 59 60 1 knn_constant
#> 122 61 62 1 61 62 1 knn_constant
#> 126 63 64 1 63 64 1 knn_constant
#> relation_name directed
#> 1 knn2 FALSE
#> 2 knn2 FALSE
#> 3 knn2 FALSE
#> 5 knn2 FALSE
#> 6 knn2 FALSE
#> 7 knn2 FALSE
#> 9 knn2 FALSE
#> 10 knn2 FALSE
#> 11 knn2 FALSE
#> 13 knn2 FALSE
#> 14 knn2 FALSE
#> 15 knn2 FALSE
#> 18 knn2 FALSE
#> 22 knn2 FALSE
#> 26 knn2 FALSE
#> 30 knn2 FALSE
#> 33 knn2 FALSE
#> 34 knn2 FALSE
#> 35 knn2 FALSE
#> 37 knn2 FALSE
#> 38 knn2 FALSE
#> 39 knn2 FALSE
#> 41 knn2 FALSE
#> 42 knn2 FALSE
#> 43 knn2 FALSE
#> 45 knn2 FALSE
#> 46 knn2 FALSE
#> 47 knn2 FALSE
#> 50 knn2 FALSE
#> 54 knn2 FALSE
#> 58 knn2 FALSE
#> 62 knn2 FALSE
#> 65 knn2 FALSE
#> 66 knn2 FALSE
#> 67 knn2 FALSE
#> 69 knn2 FALSE
#> 70 knn2 FALSE
#> 71 knn2 FALSE
#> 73 knn2 FALSE
#> 74 knn2 FALSE
#> 75 knn2 FALSE
#> 77 knn2 FALSE
#> 78 knn2 FALSE
#> 79 knn2 FALSE
#> 82 knn2 FALSE
#> 86 knn2 FALSE
#> 90 knn2 FALSE
#> 94 knn2 FALSE
#> 97 knn2 FALSE
#> 98 knn2 FALSE
#> 99 knn2 FALSE
#> 101 knn2 FALSE
#> 102 knn2 FALSE
#> 103 knn2 FALSE
#> 105 knn2 FALSE
#> 106 knn2 FALSE
#> 107 knn2 FALSE
#> 109 knn2 FALSE
#> 110 knn2 FALSE
#> 111 knn2 FALSE
#> 114 knn2 FALSE
#> 118 knn2 FALSE
#> 122 knn2 FALSE
#> 126 knn2 FALSE
