% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/add_spatial_relations.R
\name{add_spatial_knn}
\alias{add_spatial_knn}
\title{Add k-nearest-neighbours spatial relations}
\usage{
add_spatial_knn(
  x,
  coords = NULL,
  k = 8,
  name = "knn",
  weight_mode = c("constant", "inverse", "inverse_sq"),
  distance_eps = 1e-09
)
}
\arguments{
\item{x}{A \code{Problem} object created with \code{\link{create_problem}}.}

\item{coords}{Optional coordinates specification. This may be:
\itemize{
\item a \code{data.frame(id, x, y)}, or
\item a numeric matrix with two columns \code{(x, y)} aligned to the
order of planning units.
}
If \code{NULL}, coordinates are taken from \code{x$data$pu_coords} or from
columns \code{x$data$pu$x} and \code{x$data$pu$y}.}

\item{k}{Integer giving the number of neighbours per planning unit. Must be
at least 1 and strictly less than the number of planning units.}

\item{name}{Character string giving the key under which the relation is
stored.}

\item{weight_mode}{Character string indicating how distance is converted to
weight. Must be one of \code{"constant"}, \code{"inverse"}, or
\code{"inverse_sq"}.}

\item{distance_eps}{Small positive numeric constant used to avoid division by
zero in inverse-distance weighting.}
}
\value{
An updated \code{Problem} object.
}
\description{
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 \code{Problem} object.
}
\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 \eqn{s_i = (x_i, y_i)} denote the coordinates of planning unit
\eqn{i}. For each planning unit, this function identifies the \code{k}
nearest distinct planning units under Euclidean distance.

If \eqn{d_{ij}} denotes the Euclidean distance between units \eqn{i} and
\eqn{j}, then the k-nearest-neighbours relation is constructed by adding an
edge from \eqn{i} to each of its \code{k} nearest neighbours.

Edge weights are then assigned according to \code{weight_mode}:
\itemize{
\item \code{"constant"}:
\deqn{\omega_{ij} = 1,}
\item \code{"inverse"}:
\deqn{\omega_{ij} = \frac{1}{\max(d_{ij}, \varepsilon)},}
\item \code{"inverse_sq"}:
\deqn{\omega_{ij} = \frac{1}{\max(d_{ij}, \varepsilon)^2},}
}
where \eqn{\varepsilon} = \code{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
\code{\link{add_spatial_relations}}, which collapses duplicate unordered
pairs.

If the \pkg{RANN} package is available, it is used for efficient nearest
neighbour search. Otherwise, a full distance matrix is computed.
}
\examples{
pu_tbl <- data.frame(
  id = 1:4,
  cost = c(1, 2, 3, 4),
  x = c(0, 1, 0, 1),
  y = c(0, 0, 1, 1)
)

feat_tbl <- data.frame(
  id = 1:2,
  name = c("feature_1", "feature_2")
)

dist_feat_tbl <- data.frame(
  pu = c(1, 1, 2, 3, 4),
  feature = c(1, 2, 2, 1, 2),
  amount = c(5, 2, 3, 4, 1)
)

p <- create_problem(
  pu = pu_tbl,
  features = feat_tbl,
  dist_features = dist_feat_tbl,
  cost = "cost"
)

p <- add_spatial_knn(
  x = p,
  k = 2,
  name = "knn2",
  weight_mode = "constant"
)

p$data$spatial_relations$knn2

}
\seealso{
\code{\link{add_spatial_distance}},
\code{\link{add_spatial_relations}}
}
