-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathget_multi_paths.R
89 lines (72 loc) · 3.32 KB
/
get_multi_paths.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#' Compute all shortest paths between origin and destination nodes.
#'
#' @param Graph An object generated by \link{makegraph} or \link{cpp_simplify} function.
#' @param from A vector of one or more vertices from which shortest paths are calculated (origin).
#' @param to A vector of one or more vertices (destination).
#' @param keep numeric or character. Vertices of interest that will be returned.
#' @param long logical. If \code{TRUE}, a long data.frame is returned instead of a list.
#' @return List or a data.frame containing shortest paths.
#' @details \code{get_multi_paths()} recursively perform Dijkstra algorithm for each 'from' nodes. It is the equivalent of \link{get_distance_matrix}, but it return the shortest path node sequence instead of the distance.
#'
#' This algorithm is \strong{multithreaded.} Please use \code{RcppParallel::setThreadOptions()} to set the number of threads.
#'
#' @note Be aware that if 'from' and 'to' have consequent size, output will require much memory space.
#' @seealso \link{get_path_pair}, \link{get_isochrone}, \link{get_detour}
#' @examples
#' #Choose number of cores used by cppRouting
#' RcppParallel::setThreadOptions(numThreads = 1)
#'
#' #Data describing edges of the graph
#' edges<-data.frame(from_vertex=c(0,0,1,1,2,2,3,4,4),
#' to_vertex=c(1,3,2,4,4,5,1,3,5),
#' cost=c(9,2,11,3,5,12,4,1,6))
#'
#' #Get all nodes
#' nodes<-unique(c(edges$from_vertex,edges$to_vertex))
#'
#' #Construct directed graph
#' directed_graph<-makegraph(edges,directed=TRUE)
#'
#' #Get all shortest paths (node sequences) between all nodes
#' dir_paths<-get_multi_paths(Graph=directed_graph, from=nodes, to=nodes)
#' print(dir_paths)
#'
#' #Get the same result in data.frame format
#' dir_paths_df<-get_multi_paths(Graph=directed_graph, from=nodes, to=nodes, long = TRUE)
#' print(dir_paths_df)
get_multi_paths<-function(Graph, from ,to ,keep=NULL, long=FALSE){
if (length(Graph) != 5) stop("Input should be generated by makegraph() or cpp_simplify() function")
if (any(is.na(cbind(from,to)))) stop("NAs are not allowed in origin/destination nodes")
from<-as.character(from)
to<-as.character(to)
allnodes<-c(from,to)
if (sum(allnodes %in% Graph$dict$ref)<length(allnodes)) stop("Some nodes are not in the graph")
#Nodes to keep
if (!is.null(keep)) {
to_keep<-rep(0,Graph$nbnode)
keep<-as.character(keep)
to_keep[Graph$dict$ref %in% keep]<-1
}else{
to_keep<-rep(1,Graph$nbnode)
}
from_id<-Graph$dict$id[match(from,Graph$dict$ref)]
to_id<-Graph$dict$id[match(to,Graph$dict$ref)]
if (length(from_id) > length(to_id)){
res <- cpppathmat(Graph$data$to, Graph$data$from, Graph$data$dist, Graph$nbnode, Graph$dict$ref, to_keep, to_id, from_id, 0, FALSE, 0, TRUE)
} else{
res <- cpppathmat(Graph$data$from, Graph$data$to, Graph$data$dist, Graph$nbnode, Graph$dict$ref, to_keep, from_id, to_id, 0, FALSE, 0, FALSE)
}
names(res)<-from
for (i in 1:length(res)) names(res[[i]])<-to
if (long){
res<-lapply(res,function(x){
return(stack(setNames(x,names(x))))
})
res<-data.table::rbindlist(res,idcol=TRUE)
res<-res[,c(1,3,2)]
res$ind<-as.character(res$ind)
colnames(res)<-c("from","to","node")
res<-data.frame(res)
}
return(res)
}