Distances on Directed Graphs in R
at main 852 lines 31 kB view raw
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}