Distances on Directed Graphs in R
at main 732 lines 26 kB view raw
1// Modified functions from run_sp.cpp to calculate categorical distances along 2// defined kinds of ways (issue #144) 3 4#include "run_sp.h" 5 6#include "dgraph.h" 7#include "heaps/heap_lib.h" 8#include <unordered_set> 9 10// # nocov start 11template <typename T> 12void inst_graph (std::shared_ptr<DGraph> g, size_t nedges, 13 const std::map <std::string, size_t>& vert_map, 14 const std::vector <std::string>& from, 15 const std::vector <std::string>& to, 16 const std::vector <size_t>& edge_type, 17 const std::vector <T>& dist, 18 const std::vector <T>& wt) 19{ 20 for (size_t i = 0; i < nedges; ++i) 21 { 22 size_t fromi = vert_map.at(from [i]); 23 size_t toi = vert_map.at(to [i]); 24 g->addNewEdge (fromi, toi, dist [i], wt [i], edge_type [i]); 25 } 26} 27// # nocov end 28 29struct OneCategoricalDist : public RcppParallel::Worker 30{ 31 RcppParallel::RVector <int> dp_fromi; 32 const std::vector <size_t> toi; 33 const std::vector <size_t> edge_type; 34 const size_t nverts; 35 const std::vector <double> vx; 36 const std::vector <double> vy; 37 const std::shared_ptr <DGraph> g; 38 const std::string heap_type; 39 const size_t num_edge_types; 40 41 RcppParallel::RMatrix <double> dout; 42 43 // constructor 44 OneCategoricalDist ( 45 const RcppParallel::RVector <int> fromi, 46 const std::vector <size_t> toi_in, 47 const std::vector <size_t> edge_type_in, 48 const size_t nverts_in, 49 const std::vector <double> vx_in, 50 const std::vector <double> vy_in, 51 const std::shared_ptr <DGraph> g_in, 52 const std::string & heap_type_in, 53 const size_t & num_edge_types_in, 54 RcppParallel::RMatrix <double> dout_in) : 55 dp_fromi (fromi), toi (toi_in), edge_type (edge_type_in), 56 nverts (nverts_in), vx (vx_in), vy (vy_in), 57 g (g_in), heap_type (heap_type_in), 58 num_edge_types (num_edge_types_in), 59 dout (dout_in) 60 { 61 } 62 63 // Parallel function operator 64 void operator() (std::size_t begin, std::size_t end) 65 { 66 for (std::size_t i = begin; i < end; i++) 67 { 68 std::shared_ptr<PF::PathFinder> pathfinder = 69 std::make_shared <PF::PathFinder> (nverts, 70 *run_sp::getHeapImpl (heap_type), g); 71 std::vector <double> w (nverts); 72 std::vector <double> d (nverts * (num_edge_types + 1)); 73 std::vector <long int> prev (nverts); 74 75 std::vector <double> heuristic (nverts, 0.0); 76 77 size_t from_i = static_cast <size_t> (dp_fromi [i]); 78 79 // only implemented for spatial graphs 80 for (size_t j = 0; j < nverts; j++) 81 { 82 const double dx = vx [j] - vx [from_i], 83 dy = vy [j] - vy [from_i]; 84 heuristic [j] = sqrt (dx * dx + dy * dy); 85 } 86 pathfinder->AStarEdgeType (d, w, prev, heuristic, from_i, toi); 87 88 for (size_t j = 0; j < toi.size (); j++) 89 { 90 for (size_t k = 0; k <= num_edge_types; k++) { 91 const double dto = d [toi [j] + k * nverts]; 92 if (dto < INFINITE_DOUBLE) 93 { 94 dout (i, j + k * toi.size ()) = dto; 95 } 96 } 97 } 98 } 99 } 100 101}; 102 103struct OnePairedCategoricalDist : public RcppParallel::Worker 104{ 105 RcppParallel::RVector <int> dp_fromi; 106 const std::vector <size_t> toi; 107 const std::vector <size_t> edge_type; 108 const size_t nverts; 109 const std::vector <double> vx; 110 const std::vector <double> vy; 111 const std::shared_ptr <DGraph> g; 112 const std::string heap_type; 113 const size_t num_edge_types; 114 115 RcppParallel::RMatrix <double> dout; 116 117 // constructor 118 OnePairedCategoricalDist ( 119 const RcppParallel::RVector <int> fromi, 120 const std::vector <size_t> toi_in, 121 const std::vector <size_t> edge_type_in, 122 const size_t nverts_in, 123 const std::vector <double> vx_in, 124 const std::vector <double> vy_in, 125 const std::shared_ptr <DGraph> g_in, 126 const std::string & heap_type_in, 127 const size_t & num_edge_types_in, 128 RcppParallel::RMatrix <double> dout_in) : 129 dp_fromi (fromi), toi (toi_in), edge_type (edge_type_in), 130 nverts (nverts_in), vx (vx_in), vy (vy_in), 131 g (g_in), heap_type (heap_type_in), 132 num_edge_types (num_edge_types_in), 133 dout (dout_in) 134 { 135 } 136 137 // Parallel function operator 138 void operator() (std::size_t begin, std::size_t end) 139 { 140 for (std::size_t i = begin; i < end; i++) 141 { 142 std::shared_ptr<PF::PathFinder> pathfinder = 143 std::make_shared <PF::PathFinder> (nverts, 144 *run_sp::getHeapImpl (heap_type), g); 145 std::vector <double> w (nverts); 146 std::vector <double> d (nverts * (num_edge_types + 1)); 147 std::vector <long int> prev (nverts); 148 149 std::vector <double> heuristic (nverts, 0.0); 150 151 const size_t from_i = static_cast <size_t> (dp_fromi [i]); 152 const std::vector <size_t> to_i = { toi [i] }; 153 154 // only implemented for spatial graphs 155 for (size_t j = 0; j < nverts; j++) 156 { 157 const double dx = vx [j] - vx [from_i], 158 dy = vy [j] - vy [from_i]; 159 heuristic [j] = sqrt (dx * dx + dy * dy); 160 } 161 pathfinder->AStarEdgeType (d, w, prev, heuristic, from_i, to_i); 162 163 for (size_t k = 0; k <= num_edge_types; k++) 164 { 165 const double dto = d [to_i [0] + k * nverts]; 166 if (dto < INFINITE_DOUBLE) 167 dout (i, k) = dto; 168 } 169 } 170 } 171}; 172 173// Modified version of OneCategoricalDist to aggregate only a vector of 174// distances, one value for each `from`. 175struct OneCategory : public RcppParallel::Worker 176{ 177 RcppParallel::RVector <int> dp_fromi; 178 const std::vector <size_t> toi; 179 const std::vector <size_t> edge_type; 180 const size_t nverts; 181 const std::vector <double> vx; 182 const std::vector <double> vy; 183 const std::shared_ptr <DGraph> g; 184 const std::string heap_type; 185 const size_t num_edge_types; 186 187 RcppParallel::RMatrix <double> dout; 188 189 // constructor 190 OneCategory ( 191 const RcppParallel::RVector <int> fromi, 192 const std::vector <size_t> toi_in, 193 const std::vector <size_t> edge_type_in, 194 const size_t nverts_in, 195 const std::vector <double> vx_in, 196 const std::vector <double> vy_in, 197 const std::shared_ptr <DGraph> g_in, 198 const std::string & heap_type_in, 199 const size_t & num_edge_types_in, 200 RcppParallel::RMatrix <double> dout_in) : 201 dp_fromi (fromi), toi (toi_in), edge_type (edge_type_in), 202 nverts (nverts_in), vx (vx_in), vy (vy_in), 203 g (g_in), heap_type (heap_type_in), 204 num_edge_types (num_edge_types_in), 205 dout (dout_in) 206 { 207 } 208 209 // Parallel function operator 210 void operator() (std::size_t begin, std::size_t end) 211 { 212 for (std::size_t i = begin; i < end; i++) 213 { 214 std::shared_ptr<PF::PathFinder> pathfinder = 215 std::make_shared <PF::PathFinder> (nverts, 216 *run_sp::getHeapImpl (heap_type), g); 217 std::vector <double> w (nverts); 218 std::vector <double> d (nverts * (num_edge_types + 1)); 219 std::vector <long int> prev (nverts); 220 221 std::vector <double> heuristic (nverts, 0.0); 222 223 size_t from_i = static_cast <size_t> (dp_fromi [i]); 224 225 // only implemented for spatial graphs 226 for (size_t j = 0; j < nverts; j++) 227 { 228 const double dx = vx [j] - vx [from_i], 229 dy = vy [j] - vy [from_i]; 230 heuristic [j] = sqrt (dx * dx + dy * dy); 231 } 232 pathfinder->AStarEdgeType (d, w, prev, heuristic, from_i, toi); 233 234 for (size_t j = 0; j < toi.size (); j++) 235 { 236 for (size_t k = 0; k <= num_edge_types; k++) 237 { 238 const double dto = d [toi [j] + k * nverts]; 239 if (dto < INFINITE_DOUBLE) { 240 if (Rcpp::NumericMatrix::is_na (dout (i, k))) 241 dout (i, k) = dto; 242 else 243 dout (i, k) += dto; 244 } 245 } 246 } 247 } 248 } 249 250}; 251 252// Modified version of OneCategory to aggregate vector of categorical 253// distances out to a specified threshold, one value for each `from`. 254struct OneCatThreshold : public RcppParallel::Worker 255{ 256 RcppParallel::RVector <int> dp_fromi; 257 const std::vector <size_t> edge_type; 258 const size_t nverts; 259 const std::shared_ptr <DGraph> g; 260 const std::string heap_type; 261 const size_t num_edge_types; 262 const double dlimit; 263 264 RcppParallel::RMatrix <double> dout; 265 266 // constructor 267 OneCatThreshold ( 268 const RcppParallel::RVector <int> fromi, 269 const std::vector <size_t> edge_type_in, 270 const size_t nverts_in, 271 const std::shared_ptr <DGraph> g_in, 272 const std::string & heap_type_in, 273 const size_t & num_edge_types_in, 274 const double & dlimit_in, 275 RcppParallel::RMatrix <double> dout_in) : 276 dp_fromi (fromi), edge_type (edge_type_in), nverts (nverts_in), 277 g (g_in), heap_type (heap_type_in), 278 num_edge_types (num_edge_types_in), dlimit (dlimit_in), 279 dout (dout_in) 280 { 281 } 282 283 // Parallel function operator 284 void operator() (std::size_t begin, std::size_t end) 285 { 286 for (std::size_t i = begin; i < end; i++) 287 { 288 std::shared_ptr<PF::PathFinder> pathfinder = 289 std::make_shared <PF::PathFinder> (nverts, 290 *run_sp::getHeapImpl (heap_type), g); 291 std::vector <double> w (nverts); 292 std::vector <double> d (nverts * (num_edge_types + 1)); 293 std::vector <long int> prev (nverts); 294 295 size_t from_i = static_cast <size_t> (dp_fromi [i]); 296 297 pathfinder->DijkstraLimitEdgeType (d, w, prev, from_i, dlimit); 298 299 // Get the set of terminal vertices: those with w < dlimit_max but 300 // with no previous (outward-going) nodes 301 std::unordered_set <size_t> terminal_verts; 302 for (size_t j = 0; j < nverts; j++) 303 { 304 if (prev [j] == INFINITE_INT && w [j] < dlimit) 305 { 306 terminal_verts.emplace (j); 307 } 308 } 309 310 for (size_t j = 0; j < nverts; j++) 311 { 312 if (w [j] < INFINITE_DOUBLE) 313 { 314 size_t st_prev = static_cast <size_t> (prev [j]); 315 316 bool is_terminal = 317 terminal_verts.find (j) != terminal_verts.end () || 318 (d [j] > dlimit && d [st_prev] < dlimit); 319 320 if (is_terminal) { 321 322 for (size_t k = 0; k <= num_edge_types; k++) 323 { 324 const double dto = d [j + k * nverts]; 325 if (dto < INFINITE_DOUBLE) { 326 if (Rcpp::NumericMatrix::is_na (dout (i, k))) 327 dout (i, k) = dto; 328 else 329 dout (i, k) += dto; 330 } 331 } 332 } 333 } 334 } 335 } 336 } 337 338}; 339 340size_t categorical::get_num_edge_types (const std::vector <size_t> &edge_type) 341{ 342 std::unordered_set <size_t> type_set; 343 for (auto e: edge_type) 344 if (e != 0L) 345 type_set.emplace (e); 346 347 return type_set.size (); 348} 349 350void PF::PathFinder::AStarEdgeType (std::vector<double>& d, 351 std::vector<double>& w, 352 std::vector<long int>& prev, 353 const std::vector<double>& heur, 354 const size_t v0, 355 const std::vector <size_t> &to_index) 356{ 357 // d is already nverts * num_edge_types, and init_arrays only fills without 358 // resizing. 359 const DGraphEdge *edge; 360 361 const size_t nverts = m_graph->nVertices(); 362 const std::vector<DGraphVertex>& vertices = m_graph->vertices(); 363 364 PF::PathFinder::init_arrays (d, w, prev, m_open, m_closed, v0, nverts); 365 m_heap->insert (v0, heur [v0]); 366 // initialise v0 values for all edge_types 367 const size_t num_edge_types = d.size () / nverts - 1L; 368 for (size_t i = 1; i <= num_edge_types; i++) 369 d [v0 + i * nverts] = 0.0; 370 371 size_t n_reached = 0; 372 const size_t n_targets = to_index.size (); 373 bool *is_target = new bool [nverts]; 374 std::fill (is_target, is_target + nverts, false); 375 for (auto t: to_index) 376 is_target [t] = true; 377 378 while (m_heap->nItems() > 0) { 379 size_t v = m_heap->deleteMin(); 380 381 m_closed [v] = true; 382 m_open [v] = false; 383 384 edge = vertices [v].outHead; 385 scan_edge_types_heur (edge, d, w, prev, m_open, m_closed, v, heur); 386 387 if (is_target [v]) 388 n_reached++; 389 if (n_reached == n_targets) 390 break; 391 } // end while m_heap->nItems 392 delete [] is_target; 393} 394 395 396void PF::PathFinder::scan_edge_types_heur (const DGraphEdge *edge, 397 std::vector<double>& d, 398 std::vector<double>& w, 399 std::vector<long int>& prev, 400 bool *m_open_vec, 401 const bool *m_closed_vec, 402 const size_t &v0, 403 const std::vector<double> &heur) // heuristic for A* 404{ 405 const size_t nverts = w.size (); 406 const size_t num_edge_types = d.size () / nverts - 1L; 407 408 while (edge) { 409 410 const size_t et = edge->target; 411 const size_t edge_id = edge->edge_id; 412 413 if (!m_closed_vec [et]) 414 { 415 double wt = w [v0] + edge->wt; 416 if (wt < w [et]) { 417 d [et] = d [v0] + edge->dist; 418 // iterate over rest of matrix for each edge_type 419 for (size_t i = 1; i <= num_edge_types; i++) { 420 if (i == edge_id) 421 d [et + i * nverts] = d [v0 + i * nverts] + edge->dist; 422 else // carry over without incrementing dist 423 d [et + i * nverts] = d [v0 + i * nverts]; 424 } 425 426 w [et] = wt; 427 prev [et] = static_cast <int> (v0); 428 429 if (m_open_vec [et]) { 430 m_heap->decreaseKey(et, wt + heur [et] - heur [v0]); 431 } 432 else { 433 m_heap->insert (et, wt + heur [et] - heur [v0]); 434 m_open_vec [et] = true; 435 } 436 } else 437 m_closed [et] = true; 438 } 439 edge = edge->nextOut; 440 } 441} 442 443// Modified pathfinder only out to specified distance limit. Done as separate 444// routine to avoid costs of the `if` clause in general non-limited case. 445void PF::PathFinder::DijkstraLimitEdgeType ( 446 std::vector<double>& d, 447 std::vector<double>& w, 448 std::vector<long int>& prev, 449 const size_t v0, 450 const double &dlim) 451{ 452 const DGraphEdge *edge; 453 454 const size_t n = m_graph->nVertices(); 455 const std::vector<DGraphVertex>& vertices = m_graph->vertices(); 456 457 PF::PathFinder::init_arrays (d, w, prev, m_open, m_closed, v0, n); 458 m_heap->insert (v0, 0.0); 459 // initialise v0 values for all edge_types 460 const size_t num_edge_types = d.size () / n - 1L; 461 const size_t nverts = w.size (); 462 for (size_t i = 1; i <= num_edge_types; i++) 463 d [v0 + i * nverts] = 0.0; 464 465 while (m_heap->nItems() > 0) { 466 size_t v = m_heap->deleteMin(); 467 468 m_closed [v] = true; 469 m_open [v] = false; 470 471 // explore the OUT set of v only if distances are < threshold 472 bool explore = false; 473 edge = vertices [v].outHead; 474 while (edge) { 475 if ((d [v] + edge->dist) <= dlim) 476 { 477 explore = true; 478 break; 479 } 480 edge = edge->nextOut; 481 } 482 483 if (explore) 484 { 485 edge = vertices [v].outHead; 486 scan_edge_types (edge, d, w, prev, m_open, m_closed, v); 487 } 488 } // end while nItems > 0 489} 490 491void PF::PathFinder::scan_edge_types (const DGraphEdge *edge, 492 std::vector<double>& d, 493 std::vector<double>& w, 494 std::vector<long int>& prev, 495 bool *m_open_vec, 496 const bool *m_closed_vec, 497 const size_t &v0) 498{ 499 const size_t n = w.size (); 500 const size_t num_edge_types = d.size () / n - 1L; 501 502 while (edge) { 503 504 const size_t et = edge->target; 505 const size_t edge_id = edge->edge_id; 506 507 if (!m_closed_vec [et]) 508 { 509 double wt = w [v0] + edge->wt; 510 if (wt < w [et]) { 511 d [et] = d [v0] + edge->dist; 512 // iterate over rest of matrix for each edge_type 513 for (size_t i = 1; i <= num_edge_types; i++) { 514 if (i == edge_id) 515 d [et + edge_id * n] = d [v0 + edge_id * n] + edge->dist; 516 else // carry over without incrementing dist 517 d [et + i * n] = d [v0 + i * n]; 518 } 519 520 w [et] = wt; 521 prev [et] = static_cast <int> (v0); 522 523 if (m_open_vec [et]) { 524 m_heap->decreaseKey(et, wt); 525 } 526 else { 527 m_heap->insert (et, wt); 528 m_open_vec [et] = true; 529 } 530 } else 531 m_closed [et] = true; 532 } 533 edge = edge->nextOut; 534 } 535} 536 537//' rcpp_get_sp_dists_categorical 538//' 539//' The `graph` must have an `edge_type` column of non-negative integers, 540//' with 0 denoting edges which are not aggregated, and all other values 541//' defining aggregation categories. 542//' 543//' Implemented in parallal form only; no single-threaded version, and 544//' only for AStar (so graphs must be spatial). 545//' @noRd 546// [[Rcpp::export]] 547Rcpp::NumericMatrix rcpp_get_sp_dists_categorical (const Rcpp::DataFrame graph, 548 const Rcpp::DataFrame vert_map_in, 549 Rcpp::IntegerVector fromi, 550 Rcpp::IntegerVector toi_in, 551 const std::string& heap_type, 552 const bool proportions_only) 553{ 554 std::vector <size_t> toi = 555 Rcpp::as <std::vector <size_t> > ( toi_in); 556 557 size_t nfrom = static_cast <size_t> (fromi.size ()); 558 size_t nto = static_cast <size_t> (toi.size ()); 559 560 const std::vector <std::string> from = graph ["from"]; 561 const std::vector <std::string> to = graph ["to"]; 562 const std::vector <double> dist = graph ["d"]; 563 const std::vector <double> wt = graph ["d_weighted"]; 564 const std::vector <size_t> edge_type = graph ["edge_type"]; 565 566 const size_t num_edge_types = categorical::get_num_edge_types (edge_type); 567 568 const size_t nedges = static_cast <size_t> (graph.nrow ()); 569 std::map <std::string, size_t> vert_map; 570 std::vector <std::string> vert_map_id = vert_map_in ["vert"]; 571 std::vector <size_t> vert_map_n = vert_map_in ["id"]; 572 const size_t nverts = run_sp::make_vert_map (vert_map_in, vert_map_id, 573 vert_map_n, vert_map); 574 575 std::vector <double> vx (nverts), vy (nverts); 576 vx = Rcpp::as <std::vector <double> > (vert_map_in ["x"]); 577 vy = Rcpp::as <std::vector <double> > (vert_map_in ["y"]); 578 579 std::shared_ptr <DGraph> g = std::make_shared <DGraph> (nverts); 580 inst_graph (g, nedges, vert_map, from, to, edge_type, dist, wt); 581 582 size_t ncol; 583 if (proportions_only) 584 ncol = num_edge_types + 1L; 585 else 586 ncol = nto * (num_edge_types + 1L); 587 588 Rcpp::NumericVector na_vec = Rcpp::NumericVector (nfrom * ncol, 589 Rcpp::NumericVector::get_na ()); 590 Rcpp::NumericMatrix dout (static_cast <int> (nfrom), 591 static_cast <int> (ncol)); 592 593 // Create parallel worker 594 size_t chunk_size = run_sp::get_chunk_size (nfrom); 595 if (proportions_only) 596 { 597 OneCategory one_dist (RcppParallel::RVector <int> (fromi), toi, 598 edge_type, nverts, vx, vy, 599 g, heap_type, num_edge_types, 600 RcppParallel::RMatrix <double> (dout)); 601 RcppParallel::parallelFor (0, nfrom, one_dist, chunk_size); 602 } else 603 { 604 OneCategoricalDist one_dist (RcppParallel::RVector <int> (fromi), 605 toi, edge_type, nverts, vx, vy, 606 g, heap_type, num_edge_types, 607 RcppParallel::RMatrix <double> (dout)); 608 RcppParallel::parallelFor (0, nfrom, one_dist, chunk_size); 609 } 610 611 return (dout); 612} 613 614//' rcpp_get_sp_dists_categ_paired 615//' 616//' Pairwise version of 'get_sp_dists_categorical'. The `graph` must have an 617//'`edge_type` column of non-negative integers, with 0 denoting edges which are 618//' not aggregated, and all other values defining aggregation categories. 619//' 620//' Implemented in parallal form only; no single-threaded version, and 621//' only for AStar (so graphs must be spatial). 622//' @noRd 623// [[Rcpp::export]] 624Rcpp::NumericMatrix rcpp_get_sp_dists_categ_paired (const Rcpp::DataFrame graph, 625 const Rcpp::DataFrame vert_map_in, 626 Rcpp::IntegerVector fromi, 627 Rcpp::IntegerVector toi_in, 628 const std::string& heap_type) 629{ 630 std::vector <size_t> toi = 631 Rcpp::as <std::vector <size_t> > ( toi_in); 632 633 size_t nfrom = static_cast <size_t> (fromi.size ()); 634 size_t nto = static_cast <size_t> (toi.size ()); 635 if (nfrom != nto) 636 { 637 Rcpp::stop ("Pairwise categorical dists require equal numbers of 'from' and 'to' points."); 638 } 639 640 const std::vector <std::string> from = graph ["from"]; 641 const std::vector <std::string> to = graph ["to"]; 642 const std::vector <double> dist = graph ["d"]; 643 const std::vector <double> wt = graph ["d_weighted"]; 644 const std::vector <size_t> edge_type = graph ["edge_type"]; 645 646 const size_t num_types = categorical::get_num_edge_types (edge_type); 647 648 const size_t nedges = static_cast <size_t> (graph.nrow ()); 649 std::map <std::string, size_t> vert_map; 650 std::vector <std::string> vert_map_id = vert_map_in ["vert"]; 651 std::vector <size_t> vert_map_n = vert_map_in ["id"]; 652 const size_t nverts = run_sp::make_vert_map (vert_map_in, vert_map_id, 653 vert_map_n, vert_map); 654 655 std::vector <double> vx (nverts), vy (nverts); 656 vx = Rcpp::as <std::vector <double> > (vert_map_in ["x"]); 657 vy = Rcpp::as <std::vector <double> > (vert_map_in ["y"]); 658 659 std::shared_ptr <DGraph> g = std::make_shared <DGraph> (nverts); 660 inst_graph (g, nedges, vert_map, from, to, edge_type, dist, wt); 661 662 const size_t ncol = num_types + 1L; 663 664 Rcpp::NumericVector na_vec = Rcpp::NumericVector (nfrom * ncol, 665 Rcpp::NumericVector::get_na ()); 666 Rcpp::NumericMatrix dout (static_cast <int> (nfrom), 667 static_cast <int> (ncol)); 668 669 // Create parallel worker 670 size_t chunk_size = run_sp::get_chunk_size (nfrom); 671 OnePairedCategoricalDist one_dist (RcppParallel::RVector <int> (fromi), 672 toi, edge_type, nverts, vx, vy, 673 g, heap_type, num_types, 674 RcppParallel::RMatrix <double> (dout)); 675 RcppParallel::parallelFor (0, nfrom, one_dist, chunk_size); 676 677 return (dout); 678} 679 680//' rcpp_get_sp_dists_cat_threshold 681//' 682//' The `graph` must have an `edge_type` column of non-negative integers, 683//' with 0 denoting edges which are not aggregated, and all other values 684//' defining aggregation categories. 685//' 686//' Implemented in parallal form only; no single-threaded version, and 687//' only for AStar (so graphs must be spatial). 688//' @noRd 689// [[Rcpp::export]] 690Rcpp::NumericMatrix rcpp_get_sp_dists_cat_threshold (const Rcpp::DataFrame graph, 691 const Rcpp::DataFrame vert_map_in, 692 Rcpp::IntegerVector fromi, 693 const double dlimit, 694 const std::string& heap_type) 695{ 696 size_t nfrom = static_cast <size_t> (fromi.size ()); 697 698 const std::vector <std::string> from = graph ["from"]; 699 const std::vector <std::string> to = graph ["to"]; 700 const std::vector <double> dist = graph ["d"]; 701 const std::vector <double> wt = graph ["d_weighted"]; 702 const std::vector <size_t> edge_type = graph ["edge_type"]; 703 704 const size_t num_types = categorical::get_num_edge_types (edge_type); 705 706 const size_t nedges = static_cast <size_t> (graph.nrow ()); 707 std::map <std::string, size_t> vert_map; 708 std::vector <std::string> vert_map_id = vert_map_in ["vert"]; 709 std::vector <size_t> vert_map_n = vert_map_in ["id"]; 710 const size_t nverts = run_sp::make_vert_map (vert_map_in, vert_map_id, 711 vert_map_n, vert_map); 712 713 std::shared_ptr <DGraph> g = std::make_shared <DGraph> (nverts); 714 inst_graph (g, nedges, vert_map, from, to, edge_type, dist, wt); 715 716 const size_t ncol = num_types + 1L; 717 718 Rcpp::NumericVector na_vec = Rcpp::NumericVector (nfrom * ncol, 719 Rcpp::NumericVector::get_na ()); 720 Rcpp::NumericMatrix dout (static_cast <int> (nfrom), 721 static_cast <int> (ncol)); 722 723 // Create parallel worker 724 size_t chunk_size = run_sp::get_chunk_size (nfrom); 725 OneCatThreshold one_dist (RcppParallel::RVector <int> (fromi), 726 edge_type, nverts, g, heap_type, 727 num_types, dlimit, 728 RcppParallel::RMatrix <double> (dout)); 729 RcppParallel::parallelFor (0, nfrom, one_dist, chunk_size); 730 731 return (dout); 732}