Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dev for #201 #203 #206

Merged
merged 11 commits into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: dodgr
Title: Distances on Directed Graphs
Version: 0.2.20
Version: 0.2.20.001
Authors@R: c(
person("Mark", "Padgham", , "mark.padgham@email.com", role = c("aut", "cre")),
person("Andreas", "Petutschnig", role = "aut"),
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export(dodgr_deduplicate_graph)
export(dodgr_distances)
export(dodgr_dists)
export(dodgr_dists_categorical)
export(dodgr_dists_nearest)
export(dodgr_flowmap)
export(dodgr_flows_aggregate)
export(dodgr_flows_disperse)
Expand Down
22 changes: 21 additions & 1 deletion R/RcppExports.R
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,14 @@ rcpp_get_sp_dists_par <- function(graph, vert_map_in, fromi, toi_in, heap_type,
.Call(`_dodgr_rcpp_get_sp_dists_par`, graph, vert_map_in, fromi, toi_in, heap_type, is_spatial)
}

#' rcpp_get_sp_dists_par
#' rcpp_get_sp_dists_nearest
#'
#' @noRd
rcpp_get_sp_dists_nearest <- function(graph, vert_map_in, fromi, toi_in, heap_type) {
.Call(`_dodgr_rcpp_get_sp_dists_nearest`, graph, vert_map_in, fromi, toi_in, heap_type)
}

#' rcpp_get_sp_dists_paired_par
#'
#' @noRd
rcpp_get_sp_dists_paired_par <- function(graph, vert_map_in, fromi, toi, heap_type, is_spatial) {
Expand Down Expand Up @@ -380,6 +387,19 @@ rcpp_get_sp_dists_categorical <- function(graph, vert_map_in, fromi, toi_in, hea
.Call(`_dodgr_rcpp_get_sp_dists_categorical`, graph, vert_map_in, fromi, toi_in, heap_type, proportions_only)
}

#' rcpp_get_sp_dists_categ_paired
#'
#' Pairwise version of 'get_sp_dists_categorical'. The `graph` must have an
#'`edge_type` column of non-negative integers, with 0 denoting edges which are
#' not aggregated, and all other values defining aggregation categories.
#'
#' Implemented in parallal form only; no single-threaded version, and
#' only for AStar (so graphs must be spatial).
#' @noRd
rcpp_get_sp_dists_categ_paired <- function(graph, vert_map_in, fromi, toi_in, heap_type) {
.Call(`_dodgr_rcpp_get_sp_dists_categ_paired`, graph, vert_map_in, fromi, toi_in, heap_type)
}

#' rcpp_get_sp_dists_cat_threshold
#'
#' The `graph` must have an `edge_type` column of non-negative integers,
Expand Down
72 changes: 50 additions & 22 deletions R/dists-categorical.R
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
#' distances and for each edge category; if `TRUE`, return single vector of
#' proportional distances, like the `summary` function applied to full
#' results. See Note.
#' @param pairwise If `TRUE`, calculate distances only between the ordered
#' pairs of `from` and `to`. In this case, neither the `proportions_only` nor
#' `dlimit` parameters have any effect, and the result is a single matrix with
#' one row for each pair of `from`-`to` points, and one column for each
#' category.
#' @param dlimit If no value to `to` is given, distances are aggregated from
#' each `from` point out to the specified distance limit (in the same units as
#' the edge distances of the input graph). `dlimit` only has any effect if `to`
Expand Down Expand Up @@ -54,14 +59,21 @@
#' sapply (d, dim)
#' # 9 distance matrices, all of same dimensions, first of which is standard
#' # distance matrix
#' # s <- summary (d) # print summary as proportions along each "edge_type"
#' s <- summary (d) # print summary as proportions along each "edge_type"
#' # or directly calculate proportions only
#' dodgr_dists_categorical (graph, from, to,
#' proportions_only = TRUE
#' )
#'
#' # Pairwise distances return single matrix with number of rows equal to 'from'
#' # / 'to', and number of columns equal to number of edge types plus one for
#' # total distances.
#' d <- dodgr_dists_categorical (graph, from, to, pairwise = TRUE)
#' class (d)
#' dim (d)
#'
#' # The 'dlimit' parameter can be used to calculate total distances along each
#' # category of edges from a set of points:
#' # category of edges from a set of points out to specified threshold:
#' dlimit <- 2000 # in metres
#' d <- dodgr_dists_categorical (graph, from, dlimit = dlimit)
#' dim (d) # length(from), length(unique(edge_type)) + 1
Expand All @@ -71,6 +83,7 @@ dodgr_dists_categorical <- function (graph,
from = NULL,
to = NULL,
proportions_only = FALSE,
pairwise = FALSE,
dlimit = NULL,
heap = "BHeap",
quiet = TRUE) {
Expand Down Expand Up @@ -144,33 +157,48 @@ dodgr_dists_categorical <- function (graph,

if (!is.null (to)) {

d <- rcpp_get_sp_dists_categorical (
graph,
vert_map,
from_index$index,
to_index$index,
heap,
proportions_only
)
if (pairwise) {

n <- length (to)
res <- rcpp_get_sp_dists_categ_paired (
graph,
vert_map,
from_index$index,
to_index$index,
heap
)
colnames (res) <- c ("total", names (edge_type_table))
rownames (res) <- paste0 (from_index$id, "-", to_index$id)

if (!proportions_only) {
} else {

res <- process_categorical_dmat (
d,
from_index,
to_index,
d <- rcpp_get_sp_dists_categorical (
graph,
vert_map,
edge_type_table
from_index$index,
to_index$index,
heap,
proportions_only
)

} else {
n <- length (to)

if (!proportions_only) {

res <- process_categorical_dmat (
d,
from_index,
to_index,
vert_map,
edge_type_table
)

} else {

res <- apply (d, 2, sum)
res [2:length (res)] <- res [2:length (res)] / res [1]
res <- res [-1]
names (res) <- names (edge_type_table)
res <- apply (d, 2, sum)
res [2:length (res)] <- res [2:length (res)] / res [1]
res <- res [-1]
names (res) <- names (edge_type_table)
}
}
} else {

Expand Down
180 changes: 180 additions & 0 deletions R/dists-nearest.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
#' Calculate vector of shortest distances from a series of 'from' points to
#' nearest one of series of 'to' points.
#'
#' @param graph `data.frame` or equivalent object representing the network
#' graph (see Notes)
#' @param from Vector or matrix of points **from** which route distances are to
#' be calculated (see Notes)
#' @param to Vector or matrix of points **to** which shortest route distances
#' are to be calculated to nearest 'to' point only.
#' @param shortest If `FALSE`, calculate distances along the \emph{fastest}
#' rather than shortest routes (see Notes).
#' @param heap Type of heap to use in priority queue. Options include
#' Fibonacci Heap (default; `FHeap`), Binary Heap (`BHeap`),
#' `Trinomial Heap (`TriHeap`), Extended Trinomial Heap
#' (`TriHeapExt`, and 2-3 Heap (`Heap23`).
#' @param parallel If `TRUE`, perform routing calculation in parallel (see
#' details)
#' @param quiet If `FALSE`, display progress messages on screen.
#' @return Vector of distances, one element for each 'from' point giving the
#' distance to the nearest 'to' point.
#'
#' @note `graph` must minimally contain three columns of `from`,
#' `to`, `dist`. If an additional column named `weight` or
#' `wt` is present, shortest paths are calculated according to values
#' specified in that column; otherwise according to `dist` values. Either
#' way, final distances between `from` and `to` points are calculated
#' by default according to values of `dist`. That is, paths between any pair of
#' points will be calculated according to the minimal total sum of `weight`
#' values (if present), while reported distances will be total sums of `dist`
#' values.
#'
#' For street networks produced with \link{weight_streetnet}, distances may also
#' be calculated along the \emph{fastest} routes with the `shortest = FALSE`
#' option. Graphs must in this case have columns of `time` and `time_weighted`.
#' Note that the fastest routes will only be approximate when derived from
#' \pkg{sf}-format data generated with the \pkg{osmdata} function
#' `osmdata_sf()`, and will be much more accurate when derived from `sc`-format
#' data generated with `osmdata_sc()`. See \link{weight_streetnet} for details.
#'
#' The `from` and `to` columns of `graph` may be either single
#' columns of numeric or character values specifying the numbers or names of
#' graph vertices, or combinations to two columns specifying geographical
#' (longitude and latitude) coordinates. In the latter case, almost any sensible
#' combination of names will be accepted (for example, `fromx, fromy`,
#' `from_x, from_y`, or `fr_lat, fr_lon`.)
#'
#' `from` and `to` values can be either two-column matrices or
#' equivalent of longitude and latitude coordinates, or else single columns
#' precisely matching node numbers or names given in `graph$from` or
#' `graph$to`. If `to` is `NULL`, pairwise distances are calculated from all
#' `from` points to all other nodes in `graph`. If both `from` and `to` are
#' `NULL`, pairwise distances are calculated between all nodes in `graph`.
#'
#' Calculations in parallel (`parallel = TRUE`) ought very generally be
#' advantageous. For small graphs, calculating distances in parallel is likely
#' to offer relatively little gain in speed, but increases from parallel
#' computation will generally markedly increase with increasing graph sizes.
#' By default, parallel computation uses the maximal number of available cores
#' or threads. This number can be reduced by specifying a value via
#' `RcppParallel::setThreadOptions (numThreads = <desired_number>)`. Parallel
#' calculations are, however, not able to be interrupted (for example, by
#' `Ctrl-C`), and can only be stopped by killing the R process.
#'
#' @family distances
#' @export
#' @examples
#' # A simple graph
#' graph <- data.frame (
#' from = c ("A", "B", "B", "B", "C", "C", "D", "D"),
#' to = c ("B", "A", "C", "D", "B", "D", "C", "A"),
#' d = c (1, 2, 1, 3, 2, 1, 2, 1)
#' )
#' dodgr_dists (graph)
#'
#' # A larger example from the included [hampi()] data.
#' graph <- weight_streetnet (hampi)
#' from <- sample (graph$from_id, size = 100)
#' to <- sample (graph$to_id, size = 50)
#' d <- dodgr_dists (graph, from = from, to = to)
#' # d is a 100-by-50 matrix of distances between `from` and `to`
#'
#' \dontrun{
#' # a more complex street network example, thanks to @chrijo; see
#' # https://github.com/ATFutures/dodgr/issues/47
#'
#' xy <- rbind (
#' c (7.005994, 51.45774), # limbeckerplatz 1 essen germany
#' c (7.012874, 51.45041)
#' ) # hauptbahnhof essen germany
#' xy <- data.frame (lon = xy [, 1], lat = xy [, 2])
#' essen <- dodgr_streetnet (pts = xy, expand = 0.2, quiet = FALSE)
#' graph <- weight_streetnet (essen, wt_profile = "foot")
#' d <- dodgr_dists (graph, from = xy, to = xy)
#' # First reason why this does not work is because the graph has multiple,
#' # disconnected components.
#' table (graph$component)
#' # reduce to largest connected component, which is always number 1
#' graph <- graph [which (graph$component == 1), ]
#' d <- dodgr_dists (graph, from = xy, to = xy)
#' # should work, but even then note that
#' table (essen$level)
#' # There are parts of the network on different building levels (because of
#' # shopping malls and the like). These may or may not be connected, so it may
#' # be necessary to filter out particular levels
#' index <- which (!(essen$level == "-1" | essen$level == "1")) # for example
#' library (sf) # needed for following sub-select operation
#' essen <- essen [index, ]
#' graph <- weight_streetnet (essen, wt_profile = "foot")
#' graph <- graph [which (graph$component == 1), ]
#' d <- dodgr_dists (graph, from = xy, to = xy)
#' }
dodgr_dists_nearest <- function (graph,
from = NULL,
to = NULL,
shortest = TRUE,
heap = "BHeap",
parallel = TRUE,
quiet = TRUE) {

graph <- tbl_to_df (graph)

hps <- get_heap (heap, graph)
heap <- hps$heap
graph <- hps$graph

graph <- preprocess_spatial_cols (graph)
gr_cols <- dodgr_graph_cols (graph)
is_spatial <- is_graph_spatial (graph)
to_from_indices <- to_from_index_with_tp (graph, from, to)
if (to_from_indices$compound) {
graph <- to_from_indices$graph_compound
}

if (!shortest) {
if (is.na (gr_cols$time_weighted)) {
stop (
"Graph does not contain a weighted time column from ",
"which to calculate fastest paths."
)
}
graph [[gr_cols$d_weighted]] <- graph [[gr_cols$time_weighted]]
}

graph <- convert_graph (graph, gr_cols)

if (!quiet) {
message ("Calculating shortest paths ... ", appendLF = FALSE)
}

if (parallel && heap == "TriHeapExt") {
if (!quiet) {
message (
"Extended TriHeaps can not be calculated in parallel; ",
"reverting to serial calculation"
)
}
parallel <- FALSE
}

d <- rcpp_get_sp_dists_nearest (
graph,
to_from_indices$vert_map,
to_from_indices$from$index,
to_from_indices$to$index,
heap
)
index <- seq_along (to_from_indices$from$index)
nearest_index <- as.integer (d [index + length (index)])
d <- d [index]
nearest_index <- match (nearest_index, to_from_indices$to$index)
nearest_ids <- to_from_indices$to$id [nearest_index]
nearest_ids <- gsub ("\\_(start|end)$", "", nearest_ids)

return (data.frame (
from = to_from_indices$from$id,
to = nearest_ids,
d = d,
stringsAsFactors = FALSE
))
}
6 changes: 5 additions & 1 deletion codemeta.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"codeRepository": "https://github.com/ATFutures/dodgr",
"issueTracker": "https://github.com/ATFutures/dodgr/issues",
"license": "https://spdx.org/licenses/GPL-3.0",
"version": "0.2.20",
"version": "0.2.20.1",
"programmingLanguage": {
"@type": "ComputerLanguage",
"name": "R",
Expand Down Expand Up @@ -340,7 +340,11 @@
},
"SystemRequirements": "C++11, GNU make"
},
<<<<<<< HEAD
"fileSize": "28156.314KB",
=======
"fileSize": "28124.324KB",
>>>>>>> 0b4bd47e1729f244d53494eaa752de8d15ccee65
"citation": [
{
"@type": "ScholarlyArticle",
Expand Down
1 change: 1 addition & 0 deletions man/dodgr_distances.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/dodgr_dists.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading