Distances on Directed Graphs in R
1
2#include "run_sp.h"
3
4#include "dgraph.h"
5#include "heaps/heap_lib.h"
6
7// # nocov start
8template <typename T>
9void inst_graph (std::shared_ptr<DGraph> g, size_t nedges,
10 const std::map <std::string, size_t>& vert_map,
11 const std::vector <std::string>& from,
12 const std::vector <std::string>& to,
13 const std::vector <T>& dist,
14 const std::vector <T>& wt)
15{
16 for (size_t i = 0; i < nedges; ++i)
17 {
18 size_t fromi = vert_map.at(from [i]);
19 size_t toi = vert_map.at(to [i]);
20 g->addNewEdge (fromi, toi, dist [i], wt [i], i);
21 }
22}
23// # nocov end
24
25// RcppParallel jobs can be chunked to a specified "grain size"; see
26// https://rcppcore.github.io/RcppParallel/#grain_size
27// This function determines chunk size such that there are at least 100 chunks
28// for a given `nfrom`.
29size_t run_sp::get_chunk_size (const size_t nfrom)
30{
31 size_t chunk_size;
32
33 if (nfrom > 1000)
34 chunk_size = 100;
35 else if (nfrom > 100)
36 chunk_size = 10;
37 else
38 chunk_size = 1;
39
40 return chunk_size;
41}
42
43
44std::shared_ptr <HeapDesc> run_sp::getHeapImpl(const std::string& heap_type)
45{
46 if (heap_type == "FHeap")
47 return std::make_shared <HeapD<FHeap> >();
48 else if (heap_type == "BHeap" || heap_type == "set") // heap not used for set
49 return std::make_shared <HeapD<BHeap> >();
50 else if (heap_type == "Heap23")
51 return std::make_shared <HeapD<Heap23> >();
52 else if (heap_type == "TriHeap")
53 return std::make_shared <HeapD<TriHeap> >();
54 else if (heap_type == "TriHeapExt")
55 return std::make_shared <HeapD<TriHeapExt> >();
56 else
57 throw std::runtime_error("invalid heap type: " + heap_type); // # nocov
58}
59
60
61struct OneDist : public RcppParallel::Worker
62{
63 RcppParallel::RVector <int> dp_fromi;
64 const std::vector <size_t> toi;
65 const size_t nverts;
66 const std::vector <double> vx;
67 const std::vector <double> vy;
68 const std::shared_ptr <DGraph> g;
69 const std::string heap_type;
70 bool is_spatial;
71
72 RcppParallel::RMatrix <double> dout;
73
74 // constructor
75 OneDist (
76 const RcppParallel::RVector <int> fromi,
77 const std::vector <size_t> toi_in,
78 const size_t nverts_in,
79 const std::vector <double> vx_in,
80 const std::vector <double> vy_in,
81 const std::shared_ptr <DGraph> g_in,
82 const std::string & heap_type_in,
83 const bool & is_spatial_in,
84 RcppParallel::RMatrix <double> dout_in) :
85 dp_fromi (fromi), toi (toi_in), nverts (nverts_in),
86 vx (vx_in), vy (vy_in),
87 g (g_in), heap_type (heap_type_in), is_spatial (is_spatial_in),
88 dout (dout_in)
89 {
90 }
91
92 // Parallel function operator
93 void operator() (std::size_t begin, std::size_t end)
94 {
95 for (std::size_t i = begin; i < end; i++)
96 {
97 std::shared_ptr<PF::PathFinder> pathfinder =
98 std::make_shared <PF::PathFinder> (nverts,
99 *run_sp::getHeapImpl (heap_type), g);
100 std::vector <double> w (nverts);
101 std::vector <double> d (nverts);
102 std::vector <long int> prev (nverts);
103
104 std::vector <double> heuristic (nverts, 0.0);
105
106 size_t from_i = static_cast <size_t> (dp_fromi [i]);
107
108 if (is_spatial)
109 {
110 for (size_t j = 0; j < nverts; j++)
111 {
112 const double dx = vx [j] - vx [from_i],
113 dy = vy [j] - vy [from_i];
114 heuristic [j] = sqrt (dx * dx + dy * dy);
115 }
116 pathfinder->AStar (d, w, prev, heuristic, from_i, toi);
117 } else if (heap_type.find ("set") == std::string::npos)
118 pathfinder->Dijkstra (d, w, prev, from_i, toi);
119 else
120 pathfinder->Dijkstra_set (d, w, prev, from_i);
121
122 for (size_t j = 0; j < toi.size (); j++)
123 {
124 if (w [toi [j]] < INFINITE_DOUBLE)
125 {
126 dout (i, j) = d [toi [j]];
127 }
128 }
129 }
130 }
131
132};
133
134struct OneDistNearest : public RcppParallel::Worker
135{
136 RcppParallel::RVector <int> dp_fromi;
137 const std::vector <size_t> toi;
138 const size_t nverts;
139 const size_t nfrom;
140 const std::shared_ptr <DGraph> g;
141 const std::string heap_type;
142
143 RcppParallel::RVector <double> dout;
144
145 // constructor
146 OneDistNearest (
147 const RcppParallel::RVector <int> fromi,
148 const std::vector <size_t> toi_in,
149 const size_t nverts_in,
150 const size_t nfrom_in,
151 const std::shared_ptr <DGraph> g_in,
152 const std::string & heap_type_in,
153 RcppParallel::RVector <double> dout_in) :
154 dp_fromi (fromi), toi (toi_in),
155 nverts (nverts_in), nfrom (nfrom_in),
156 g (g_in), heap_type (heap_type_in),
157 dout (dout_in)
158 {
159 }
160
161 // Parallel function operator
162 void operator() (std::size_t begin, std::size_t end)
163 {
164 for (std::size_t i = begin; i < end; i++)
165 {
166 std::shared_ptr<PF::PathFinder> pathfinder =
167 std::make_shared <PF::PathFinder> (nverts,
168 *run_sp::getHeapImpl (heap_type), g);
169 std::vector <double> w (nverts);
170 std::vector <double> d (nverts);
171 std::vector <long int> prev (nverts);
172
173 size_t from_i = static_cast <size_t> (dp_fromi [i]);
174
175 pathfinder->DijkstraNearest (d, w, prev, from_i, toi);
176
177 for (size_t j = 0; j < toi.size (); j++)
178 {
179 if (w [toi [j]] < INFINITE_DOUBLE)
180 {
181 dout [i] = d [toi [j]];
182 dout [i + nfrom] = toi [j];
183 }
184 }
185 }
186 }
187
188};
189
190struct OneDistPaired : public RcppParallel::Worker
191{
192 RcppParallel::RVector <int> dp_fromtoi;
193 const size_t nverts;
194 const size_t nfrom;
195 const std::vector <double> vx;
196 const std::vector <double> vy;
197 const std::shared_ptr <DGraph> g;
198 const std::string heap_type;
199 bool is_spatial;
200
201 RcppParallel::RMatrix <double> dout;
202
203 // constructor
204 OneDistPaired (
205 const RcppParallel::RVector <int> fromtoi,
206 const size_t nverts_in,
207 const size_t nfrom_in,
208 const std::vector <double> vx_in,
209 const std::vector <double> vy_in,
210 const std::shared_ptr <DGraph> g_in,
211 const std::string & heap_type_in,
212 const bool & is_spatial_in,
213 RcppParallel::RMatrix <double> dout_in) :
214 dp_fromtoi (fromtoi), nverts (nverts_in), nfrom (nfrom_in),
215 vx (vx_in), vy (vy_in),
216 g (g_in), heap_type (heap_type_in), is_spatial (is_spatial_in),
217 dout (dout_in)
218 {
219 }
220
221 // Parallel function operator
222 void operator() (std::size_t begin, std::size_t end)
223 {
224 for (std::size_t i = begin; i < end; i++)
225 {
226 std::shared_ptr<PF::PathFinder> pathfinder =
227 std::make_shared <PF::PathFinder> (nverts,
228 *run_sp::getHeapImpl (heap_type), g);
229 std::vector <double> w (nverts);
230 std::vector <double> d (nverts);
231 std::vector <long int> prev (nverts);
232
233 std::vector <double> heuristic (nverts, 0.0);
234
235 const size_t from_i = static_cast <size_t> (dp_fromtoi [i]);
236 const std::vector <size_t> to_i = {static_cast <size_t> (dp_fromtoi [nfrom + i])};
237
238 if (is_spatial)
239 {
240 // need to set an additional target vertex that is somewhat
241 // beyond the single actual target vertex. Default here is max
242 // heuristic, but reduced in following loop.
243 long int max_h_index = -1;
244 double max_h_value = -1.0;
245 for (size_t j = 0; j < nverts; j++)
246 {
247 const double dx = vx [j] - vx [from_i],
248 dy = vy [j] - vy [from_i];
249 heuristic [j] = sqrt (dx * dx + dy * dy);
250 if (heuristic [j] > max_h_value) {
251 max_h_value = heuristic [j];
252 max_h_index = static_cast <long int> (j);
253 }
254 }
255 const double htemp = heuristic [static_cast <size_t> (dp_fromtoi [nfrom + i])];
256 double min_h_value = max_h_value;
257 long int min_h_index = max_h_index;
258 // Arbitrary relative distance threshold
259 // TODO: Are there likely to be cases where this might need to
260 // be adjusted?
261 const double thr = 0.1;
262 for (size_t j = 0; j < nverts; j++) {
263 if ((heuristic [j] < (thr * htemp)) && (heuristic [j] > min_h_value)) {
264 min_h_value = heuristic [j];
265 min_h_index = static_cast <long int> (j);
266 }
267 }
268 const std::vector <size_t> to_i2 = {to_i [0], static_cast <size_t> (min_h_index)};
269 pathfinder->AStar (d, w, prev, heuristic, from_i, to_i2);
270 } else if (heap_type.find ("set") == std::string::npos)
271 pathfinder->Dijkstra (d, w, prev, from_i, to_i);
272 else
273 pathfinder->Dijkstra_set (d, w, prev, from_i);
274
275 if (w [to_i [0]] < INFINITE_DOUBLE)
276 dout (i, 0) = d [to_i [0]];
277 }
278 }
279
280};
281
282
283struct OneIso : public RcppParallel::Worker
284{
285 RcppParallel::RVector <int> dp_fromi;
286 const size_t nverts;
287 const std::shared_ptr <DGraph> g;
288 const RcppParallel::RVector <double> dlimit;
289 const std::string heap_type;
290
291 RcppParallel::RMatrix <double> dout;
292
293 // constructor
294 OneIso (
295 const RcppParallel::RVector <int> fromi,
296 const size_t nverts_in,
297 const std::shared_ptr <DGraph> g_in,
298 const RcppParallel::RVector <double> dlimit_in,
299 const std::string & heap_type_in,
300 RcppParallel::RMatrix <double> dout_in) :
301 dp_fromi (fromi), nverts (nverts_in),
302 g (g_in), dlimit (dlimit_in),
303 heap_type (heap_type_in), dout (dout_in)
304 {
305 }
306
307 // Parallel function operator
308 void operator() (std::size_t begin, std::size_t end)
309 {
310 const double dlimit_max = *std::max_element (dlimit.begin (), dlimit.end ());
311
312 for (std::size_t i = begin; i < end; i++)
313 {
314 std::shared_ptr<PF::PathFinder> pathfinder =
315 std::make_shared <PF::PathFinder> (nverts,
316 *run_sp::getHeapImpl (heap_type), g);
317 std::vector <double> w (nverts);
318 std::vector <double> d (nverts);
319 std::vector <long int> prev (nverts);
320
321 std::fill (w.begin (), w.end (), INFINITE_DOUBLE);
322 std::fill (d.begin (), d.end (), INFINITE_DOUBLE);
323 std::fill (prev.begin (), prev.end (), INFINITE_INT);
324
325 size_t from_i = static_cast <size_t> (dp_fromi [i]);
326
327 pathfinder->DijkstraLimit (d, w, prev, from_i, dlimit_max);
328
329 // Get the set of terminal vertices: those with w < dlimit_max but
330 // with no previous (outward-going) nodes
331 std::unordered_set <int> terminal_verts;
332 for (size_t j = 0; j < nverts; j++)
333 {
334 if (prev [j] == INFINITE_INT && d [j] < dlimit_max)
335 {
336 terminal_verts.emplace (static_cast <int> (j));
337 }
338 }
339
340
341 for (size_t j = 0; j < nverts; j++)
342 {
343 if (terminal_verts.find (static_cast <int> (j)) !=
344 terminal_verts.end ())
345 {
346 // Flag terminal verts with -d
347 dout (i, j) = -d [j]; // # nocov
348 } else if (prev [j] < INFINITE_INT && d [j] < dlimit_max)
349 {
350 size_t st_prev = static_cast <size_t> (prev [j]);
351 dout (i, j) = d [j];
352 }
353 }
354 }
355 }
356
357};
358
359
360size_t run_sp::make_vert_map (const Rcpp::DataFrame &vert_map_in,
361 const std::vector <std::string> &vert_map_id,
362 const std::vector <size_t> &vert_map_n,
363 std::map <std::string, size_t> &vert_map)
364{
365 for (size_t i = 0;
366 i < static_cast <size_t> (vert_map_in.nrow ()); ++i)
367 {
368 vert_map.emplace (vert_map_id [i], vert_map_n [i]);
369 }
370 size_t nverts = static_cast <size_t> (vert_map.size ());
371 return (nverts);
372}
373
374// Flows from the pathfinder output are reallocated based on matching vertex
375// pairs to edge indices. Note, however, that contracted graphs frequently
376// have duplicate vertex pairs with different distances. The following
377// therefore uses two maps, one to hold the ultimate index from vertex
378// pairs, and the other to hold minimal distances. This is used in flow routines
379// only.
380void run_sp::make_vert_to_edge_maps (const std::vector <std::string> &from,
381 const std::vector <std::string> &to, const std::vector <double> &wt,
382 std::unordered_map <std::string, size_t> &verts_to_edge_map,
383 std::unordered_map <std::string, double> &verts_to_dist_map)
384{
385 for (size_t i = 0; i < from.size (); i++)
386 {
387 std::string two_verts = "f" + from [i] + "t" + to [i];
388 verts_to_edge_map.emplace (two_verts, i);
389 if (verts_to_dist_map.find (two_verts) == verts_to_dist_map.end ())
390 verts_to_dist_map.emplace (two_verts, wt [i]);
391 else if (wt [i] < verts_to_dist_map.at (two_verts))
392 {
393 verts_to_dist_map [two_verts] = wt [i];
394 verts_to_edge_map [two_verts] = i;
395 }
396 }
397}
398
399//' rcpp_get_sp_dists_par
400//'
401//' @noRd
402// [[Rcpp::export]]
403Rcpp::NumericMatrix rcpp_get_sp_dists_par (const Rcpp::DataFrame graph,
404 const Rcpp::DataFrame vert_map_in,
405 Rcpp::IntegerVector fromi,
406 Rcpp::IntegerVector toi_in,
407 const std::string& heap_type,
408 const bool is_spatial)
409{
410 std::vector <size_t> toi =
411 Rcpp::as <std::vector <size_t> > ( toi_in);
412
413 size_t nfrom = static_cast <size_t> (fromi.size ());
414 size_t nto = static_cast <size_t> (toi.size ());
415
416 const std::vector <std::string> from = graph ["from"];
417 const std::vector <std::string> to = graph ["to"];
418 const std::vector <double> dist = graph ["d"];
419 const std::vector <double> wt = graph ["d_weighted"];
420
421 const size_t nedges = static_cast <size_t> (graph.nrow ());
422 std::map <std::string, size_t> vert_map;
423 std::vector <std::string> vert_map_id = vert_map_in ["vert"];
424 std::vector <size_t> vert_map_n = vert_map_in ["id"];
425 const size_t nverts = run_sp::make_vert_map (vert_map_in, vert_map_id,
426 vert_map_n, vert_map);
427
428 std::vector <double> vx (nverts), vy (nverts);
429 if (is_spatial)
430 {
431 vx = Rcpp::as <std::vector <double> > (vert_map_in ["x"]);
432 vy = Rcpp::as <std::vector <double> > (vert_map_in ["y"]);
433 }
434
435 std::shared_ptr <DGraph> g = std::make_shared <DGraph> (nverts);
436 inst_graph (g, nedges, vert_map, from, to, dist, wt);
437
438 Rcpp::NumericVector na_vec = Rcpp::NumericVector (nfrom * nto,
439 Rcpp::NumericVector::get_na ());
440 Rcpp::NumericMatrix dout (static_cast <int> (nfrom),
441 static_cast <int> (nto), na_vec.begin ());
442
443 // Create parallel worker
444 OneDist one_dist (RcppParallel::RVector <int> (fromi), toi,
445 nverts, vx, vy, g, heap_type, is_spatial,
446 RcppParallel::RMatrix <double> (dout));
447
448 size_t chunk_size = run_sp::get_chunk_size (nfrom);
449 RcppParallel::parallelFor (0, nfrom, one_dist, chunk_size);
450
451 return (dout);
452}
453
454//' rcpp_get_sp_dists_nearest
455//'
456//' @noRd
457// [[Rcpp::export]]
458Rcpp::NumericVector rcpp_get_sp_dists_nearest (const Rcpp::DataFrame graph,
459 const Rcpp::DataFrame vert_map_in,
460 Rcpp::IntegerVector fromi,
461 Rcpp::IntegerVector toi_in,
462 const std::string& heap_type)
463{
464 std::vector <size_t> toi =
465 Rcpp::as <std::vector <size_t> > (toi_in);
466
467 size_t nfrom = static_cast <size_t> (fromi.size ());
468
469 const std::vector <std::string> from = graph ["from"];
470 const std::vector <std::string> to = graph ["to"];
471 const std::vector <double> dist = graph ["d"];
472 const std::vector <double> wt = graph ["d_weighted"];
473
474 const size_t nedges = static_cast <size_t> (graph.nrow ());
475 std::map <std::string, size_t> vert_map;
476 std::vector <std::string> vert_map_id = vert_map_in ["vert"];
477 std::vector <size_t> vert_map_n = vert_map_in ["id"];
478 const size_t nverts = run_sp::make_vert_map (vert_map_in, vert_map_id,
479 vert_map_n, vert_map);
480
481 std::shared_ptr <DGraph> g = std::make_shared <DGraph> (nverts);
482 inst_graph (g, nedges, vert_map, from, to, dist, wt);
483
484 Rcpp::NumericVector dout = Rcpp::NumericVector (2 * nfrom,
485 Rcpp::NumericVector::get_na ());
486
487 // Create parallel worker
488 OneDistNearest one_dist (RcppParallel::RVector <int> (fromi), toi,
489 nverts, nfrom, g, heap_type,
490 RcppParallel::RVector <double> (dout));
491
492 size_t chunk_size = run_sp::get_chunk_size (nfrom);
493 RcppParallel::parallelFor (0, nfrom, one_dist, chunk_size);
494
495 return (dout);
496}
497
498//' rcpp_get_sp_dists_paired_par
499//'
500//' @noRd
501// [[Rcpp::export]]
502Rcpp::NumericMatrix rcpp_get_sp_dists_paired_par (const Rcpp::DataFrame graph,
503 const Rcpp::DataFrame vert_map_in,
504 Rcpp::IntegerVector fromi,
505 Rcpp::IntegerVector toi,
506 const std::string& heap_type,
507 const bool is_spatial)
508{
509 if (fromi.size () != toi.size ())
510 Rcpp::stop ("pairwise dists must have from.size == to.size");
511 long int n = fromi.size ();
512 size_t n_st = static_cast <size_t> (n);
513
514 const std::vector <std::string> from = graph ["from"];
515 const std::vector <std::string> to = graph ["to"];
516 const std::vector <double> dist = graph ["d"];
517 const std::vector <double> wt = graph ["d_weighted"];
518
519 const size_t nedges = static_cast <size_t> (graph.nrow ());
520 std::map <std::string, size_t> vert_map;
521 std::vector <std::string> vert_map_id = vert_map_in ["vert"];
522 std::vector <size_t> vert_map_n = vert_map_in ["id"];
523 const size_t nverts = run_sp::make_vert_map (vert_map_in, vert_map_id,
524 vert_map_n, vert_map);
525
526 std::vector <double> vx (nverts), vy (nverts);
527 if (is_spatial)
528 {
529 vx = Rcpp::as <std::vector <double> > (vert_map_in ["x"]);
530 vy = Rcpp::as <std::vector <double> > (vert_map_in ["y"]);
531 }
532
533 std::shared_ptr <DGraph> g = std::make_shared <DGraph> (nverts);
534 inst_graph (g, nedges, vert_map, from, to, dist, wt);
535
536 Rcpp::NumericVector na_vec = Rcpp::NumericVector (n_st,
537 Rcpp::NumericVector::get_na ());
538 Rcpp::NumericMatrix dout (static_cast <int> (n), 1, na_vec.begin ());
539
540 // Paired (fromi, toi) in a single vector
541 Rcpp::IntegerVector fromto (2 * n_st);
542 for (int i = 0; i < n; i++)
543 {
544 size_t i_t = static_cast <size_t> (i);
545 fromto [i] = fromi (i_t);
546 fromto [i + n] = toi (i_t);
547 }
548
549 // Create parallel worker
550 OneDistPaired one_dist_paired (RcppParallel::RVector <int> (fromto),
551 nverts, n_st, vx, vy, g, heap_type, is_spatial,
552 RcppParallel::RMatrix <double> (dout));
553
554 size_t chunk_size = run_sp::get_chunk_size (n_st);
555 RcppParallel::parallelFor (0, n_st, one_dist_paired, chunk_size);
556
557 return (dout);
558}
559
560//' rcpp_get_iso
561//'
562//' @noRd
563// [[Rcpp::export]]
564Rcpp::NumericMatrix rcpp_get_iso (const Rcpp::DataFrame graph,
565 const Rcpp::DataFrame vert_map_in,
566 Rcpp::IntegerVector fromi,
567 Rcpp::NumericVector dlim,
568 const std::string& heap_type)
569{
570 const size_t nfrom = static_cast <size_t> (fromi.size ());
571
572 std::vector <std::string> from = graph ["from"];
573 std::vector <std::string> to = graph ["to"];
574 std::vector <double> dist = graph ["d"];
575 std::vector <double> wt = graph ["d_weighted"];
576
577 size_t nedges = static_cast <size_t> (graph.nrow ());
578 std::map <std::string, size_t> vert_map;
579 std::vector <std::string> vert_map_id = vert_map_in ["vert"];
580 std::vector <size_t> vert_map_n = vert_map_in ["id"];
581 size_t nverts = run_sp::make_vert_map (vert_map_in, vert_map_id,
582 vert_map_n, vert_map);
583
584 std::vector <double> vx (nverts), vy (nverts);
585
586 std::shared_ptr <DGraph> g = std::make_shared <DGraph> (nverts);
587 inst_graph (g, nedges, vert_map, from, to, dist, wt);
588
589 Rcpp::NumericVector na_vec = Rcpp::NumericVector (nfrom * nverts,
590 Rcpp::NumericVector::get_na ());
591 Rcpp::NumericMatrix dout (static_cast <int> (nfrom),
592 static_cast <int> (nverts), na_vec.begin ());
593
594 // Create parallel worker
595 OneIso one_iso (RcppParallel::RVector <int> (fromi), nverts, g,
596 RcppParallel::RVector <double> (dlim), heap_type,
597 RcppParallel::RMatrix <double> (dout));
598
599 RcppParallel::parallelFor (0, static_cast <size_t> (fromi.length ()),
600 one_iso);
601
602 return (dout);
603}
604
605//' rcpp_get_sp_dists
606//'
607//' @noRd
608// [[Rcpp::export]]
609Rcpp::NumericMatrix rcpp_get_sp_dists (const Rcpp::DataFrame graph,
610 const Rcpp::DataFrame vert_map_in,
611 Rcpp::IntegerVector fromi,
612 Rcpp::IntegerVector toi_in,
613 const std::string& heap_type)
614{
615 std::vector <size_t> toi =
616 Rcpp::as <std::vector <size_t> > ( toi_in);
617 size_t nfrom = static_cast <size_t> (fromi.size ());
618 size_t nto = static_cast <size_t> (toi.size ());
619
620 std::vector <std::string> from = graph ["from"];
621 std::vector <std::string> to = graph ["to"];
622 std::vector <double> dist = graph ["d"];
623 std::vector <double> wt = graph ["d_weighted"];
624
625 size_t nedges = static_cast <size_t> (graph.nrow ());
626 std::map <std::string, size_t> vert_map;
627 std::vector <std::string> vert_map_id = vert_map_in ["vert"];
628 std::vector <size_t> vert_map_n = vert_map_in ["id"];
629 size_t nverts = run_sp::make_vert_map (vert_map_in, vert_map_id,
630 vert_map_n, vert_map);
631
632 std::shared_ptr<DGraph> g = std::make_shared<DGraph>(nverts);
633 inst_graph (g, nedges, vert_map, from, to, dist, wt);
634
635 std::vector<double> w (nverts);
636 std::vector<double> d (nverts);
637 std::vector<long int> prev (nverts);
638
639 // initialise dout matrix to NA
640 Rcpp::NumericVector na_vec = Rcpp::NumericVector (nfrom * nto,
641 Rcpp::NumericVector::get_na ());
642 Rcpp::NumericMatrix dout (static_cast <int> (nfrom),
643 static_cast <int> (nto), na_vec.begin ());
644
645
646 for (size_t i = 0; i < nfrom; i++)
647 {
648 // These lines (re-)initialise the heap, so have to be called for each v
649 std::shared_ptr <PF::PathFinder> pathfinder =
650 std::make_shared <PF::PathFinder> (
651 nverts, *run_sp::getHeapImpl(heap_type), g);
652
653 pathfinder->init (g); // specify the graph
654
655 Rcpp::checkUserInterrupt ();
656 std::fill (w.begin(), w.end(), INFINITE_DOUBLE);
657 std::fill (d.begin(), d.end(), INFINITE_DOUBLE);
658 size_t fromi_i = static_cast <size_t> (fromi [static_cast <R_xlen_t> (i)]);
659 d [fromi_i] = w [fromi_i] = 0.0;
660
661 pathfinder->Dijkstra (d, w, prev, fromi_i, toi);
662 for (size_t j = 0; j < nto; j++)
663 {
664 if (w [static_cast <size_t> (toi [j])] < INFINITE_DOUBLE)
665 {
666 dout (i, j) = d [static_cast <size_t> (toi [j])];
667 }
668 }
669 }
670 return (dout);
671}
672
673
674//' rcpp_get_paths
675//'
676//' @param graph The data.frame holding the graph edges
677//' @param vert_map_in map from <std::string> vertex ID to (0-indexed) integer
678//' index of vertices
679//' @param fromi Index into vert_map_in of vertex numbers
680//' @param toi Index into vert_map_in of vertex numbers
681//'
682//' @note The graph is constructed with 0-indexed vertex numbers contained in
683//' code{vert_map_in}. Both \code{fromi} and \code{toi} already map directly
684//' onto these. The graph has to be constructed by first constructing a
685//' \code{std::map} object (\code{vertmap}) for \code{vert_map_in}, then
686//' translating all \code{graph["from"/"to"]} values into these indices. This
687//' construction is done in \code{inst_graph}.
688//'
689//' @note Returns 1-indexed values indexing directly into the R input
690//'
691//' @noRd
692// [[Rcpp::export]]
693Rcpp::List rcpp_get_paths (const Rcpp::DataFrame graph,
694 const Rcpp::DataFrame vert_map_in,
695 Rcpp::IntegerVector fromi,
696 Rcpp::IntegerVector toi_in,
697 const std::string& heap_type)
698{
699 std::vector <size_t> toi =
700 Rcpp::as <std::vector <size_t> > ( toi_in);
701 size_t nfrom = static_cast <size_t> (fromi.size ());
702 size_t nto = static_cast <size_t> (toi.size ());
703
704 std::vector <std::string> from = graph ["from"];
705 std::vector <std::string> to = graph ["to"];
706 std::vector <double> dist = graph ["d"];
707 std::vector <double> wt = graph ["d_weighted"];
708
709 size_t nedges = static_cast <size_t> (graph.nrow ());
710 std::map <std::string, size_t> vert_map;
711 std::vector <std::string> vert_map_id = vert_map_in ["vert"];
712 std::vector <size_t> vert_map_n = vert_map_in ["id"];
713 size_t nverts = run_sp::make_vert_map (vert_map_in, vert_map_id,
714 vert_map_n, vert_map);
715
716 std::shared_ptr<DGraph> g = std::make_shared<DGraph>(nverts);
717 inst_graph (g, nedges, vert_map, from, to, dist, wt);
718
719 Rcpp::List res (nfrom);
720 std::vector<double> w (nverts);
721 std::vector<double> d (nverts);
722 std::vector<long int> prev (nverts);
723
724 for (size_t i = 0; i < nfrom; i++)
725 {
726 const R_xlen_t i_R = static_cast <R_xlen_t> (i);
727
728 // These lines (re-)initialise the heap, so have to be called for each i
729 std::shared_ptr<PF::PathFinder> pathfinder =
730 std::make_shared <PF::PathFinder> (nverts,
731 *run_sp::getHeapImpl(heap_type), g);
732
733 pathfinder->init (g); // specify the graph
734
735 Rcpp::checkUserInterrupt ();
736 std::fill (w.begin(), w.end(), INFINITE_DOUBLE);
737 std::fill (d.begin(), d.end(), INFINITE_DOUBLE);
738 std::fill (prev.begin(), prev.end(), INFINITE_INT);
739 d [static_cast <size_t> (fromi [i_R])] =
740 w [static_cast <size_t> (fromi [i_R])] = 0.0;
741
742 pathfinder->Dijkstra (d, w, prev,
743 static_cast <size_t> (fromi [i_R]), toi);
744
745 Rcpp::List res1 (nto);
746 for (size_t j = 0; j < nto; j++)
747 {
748 std::vector <long int> onePath;
749 if (w [toi [j]] < INFINITE_DOUBLE)
750 {
751 long int target = toi_in [static_cast <R_xlen_t> (j)]; // target can be -1!
752 while (target < INFINITE_INT)
753 {
754 // Note that targets are all C++ 0-indexed and are converted
755 // directly here to R-style 1-indexes.
756 onePath.push_back (target + 1L);
757 target = prev [static_cast <size_t> (target)];
758 if (target < 0L || target == fromi [i_R])
759 break;
760 }
761 }
762 if (onePath.size () >= 1)
763 {
764 onePath.push_back (static_cast <R_xlen_t> (fromi [i_R] + 1L));
765 std::reverse (onePath.begin (), onePath.end ());
766 res1 [static_cast <R_xlen_t> (j)] = onePath;
767 }
768 }
769 res [static_cast <R_xlen_t> (i)] = res1;
770 }
771 return (res);
772}
773
774
775// [[Rcpp::export]]
776Rcpp::List rcpp_get_paths_pairwise (const Rcpp::DataFrame graph,
777 const Rcpp::DataFrame vert_map_in,
778 Rcpp::IntegerVector fromi,
779 Rcpp::IntegerVector toi_in,
780 const std::string& heap_type)
781{
782 std::vector <size_t> toi =
783 Rcpp::as <std::vector <size_t> > ( toi_in);
784 size_t nfrom = static_cast <size_t> (fromi.size ());
785
786 std::vector <std::string> from = graph ["from"];
787 std::vector <std::string> to = graph ["to"];
788 std::vector <double> dist = graph ["d"];
789 std::vector <double> wt = graph ["d_weighted"];
790
791 size_t nedges = static_cast <size_t> (graph.nrow ());
792 std::map <std::string, size_t> vert_map;
793 std::vector <std::string> vert_map_id = vert_map_in ["vert"];
794 std::vector <size_t> vert_map_n = vert_map_in ["id"];
795 size_t nverts = run_sp::make_vert_map (vert_map_in, vert_map_id,
796 vert_map_n, vert_map);
797
798 std::shared_ptr<DGraph> g = std::make_shared<DGraph>(nverts);
799 inst_graph (g, nedges, vert_map, from, to, dist, wt);
800
801 Rcpp::List res (nfrom);
802 std::vector<double> w (nverts);
803 std::vector<double> d (nverts);
804 std::vector<long int> prev (nverts);
805
806 for (size_t i = 0; i < nfrom; i++)
807 {
808 const R_xlen_t i_R = static_cast <R_xlen_t> (i);
809
810 // These lines (re-)initialise the heap, so have to be called for each i
811 std::shared_ptr<PF::PathFinder> pathfinder =
812 std::make_shared <PF::PathFinder> (nverts,
813 *run_sp::getHeapImpl(heap_type), g);
814
815 pathfinder->init (g); // specify the graph
816
817 Rcpp::checkUserInterrupt ();
818 std::fill (w.begin(), w.end(), INFINITE_DOUBLE);
819 std::fill (d.begin(), d.end(), INFINITE_DOUBLE);
820 std::fill (prev.begin(), prev.end(), INFINITE_INT);
821 d [static_cast <size_t> (fromi [i_R])] =
822 w [static_cast <size_t> (fromi [i_R])] = 0.0;
823
824 pathfinder->Dijkstra (d, w, prev,
825 static_cast <size_t> (fromi [i_R]), toi);
826
827 Rcpp::List res1( 1L );
828 std::vector <long int> onePath;
829
830 if (w [toi [i]] < INFINITE_DOUBLE)
831 {
832 long int target = toi_in [i_R]; // target can be -1!
833 while (target < INFINITE_INT)
834 {
835 // Note that targets are all C++ 0-indexed and are converted
836 // directly here to R-style 1-indexes.
837 onePath.push_back (target + 1);
838 target = prev [static_cast <size_t> (target)];
839 if (target < 0 || target == fromi [i_R])
840 break;
841 }
842 }
843 if (onePath.size () >= 1)
844 {
845 onePath.push_back (static_cast <R_xlen_t> (fromi [i_R] + 1L));
846 std::reverse (onePath.begin (), onePath.end ());
847 res1[0L] = onePath;
848 }
849 res [static_cast <R_xlen_t> (i)] = res1;
850 }
851 return (res);
852}