16 #ifndef POPS_NETWORK_KERNEL_HPP
17 #define POPS_NETWORK_KERNEL_HPP
50 template<
typename RasterIndex>
92 std::pair<RasterIndex, RasterIndex>
xy_to_row_col(
double x,
double y)
const
96 return {std::floor(row), std::floor(col)};
102 std::pair<RasterIndex, RasterIndex>
141 template<
typename InputStream>
143 InputStream& node_stream, InputStream& segment_stream,
bool allow_empty =
false)
145 std::set<NodeId> node_ids;
147 if (node_ids.empty()) {
151 throw std::runtime_error(
"Network: No nodes within the extend");
166 const std::set<NodeId>&
get_nodes_at(RasterIndex row, RasterIndex col)
const
172 static std::set<NodeId> empty;
188 template<
typename Generator>
193 auto num_nodes = nodes.size();
194 if (num_nodes == 1) {
195 return *nodes.begin();
197 else if (num_nodes > 1) {
201 throw std::invalid_argument(
"No nodes at a given row and column");
232 throw std::invalid_argument(
"No node with a given id");
243 template<
typename Generator>
245 travel(RasterIndex row, RasterIndex col,
double time, Generator& generator)
const
250 std::set<NodeId> visited_nodes;
252 auto next_node_id =
next_node(node_id, visited_nodes, generator);
253 visited_nodes.insert(node_id);
255 if (next_node_id == node_id)
256 return std::make_tuple(row, col);
259 for (
const auto& cell : segment) {
268 node_id = next_node_id;
270 throw std::invalid_argument(
"Time must be greater than or equal to zero");
283 std::vector<std::pair<NodeId, std::pair<RasterIndex, RasterIndex>>>
286 std::vector<std::pair<NodeId, std::pair<RasterIndex, RasterIndex>>> nodes;
289 RasterIndex row = item.first.first;
290 RasterIndex col = item.first.second;
291 for (
const auto node_id : item.second) {
292 nodes.emplace_back(node_id, std::make_pair(row, col));
307 std::map<std::string, int> stats;
308 std::set<NodeId> node_ids;
310 for (
const auto node_id : item.second) {
311 node_ids.insert(node_id);
314 stats[
"num_nodes"] = node_ids.size();
317 std::set<NodeId> nodes_with_segments;
319 nodes_with_segments.insert(item.first);
321 stats[
"num_nodes_with_segments"] = nodes_with_segments.size();
323 int num_standalone_nodes = 0;
324 for (
NodeId node_id : node_ids) {
325 if (nodes_with_segments.find(node_id) == nodes_with_segments.end()) {
326 stats[
"standalone_node_" + std::to_string(++num_standalone_nodes)] =
330 stats[
"num_standalone_nodes"] = num_standalone_nodes;
333 const auto minmax_node_id = minmax_element(node_ids.begin(), node_ids.end());
334 stats[
"min_node_id"] = *minmax_node_id.first;
335 stats[
"max_node_id"] = *minmax_node_id.second;
344 template<
typename OutputStream>
347 stream <<
"network:\n";
348 stream <<
" statistics:\n";
350 for (
const auto& item : stats) {
351 stream <<
" " << item.first <<
": " << item.second <<
"\n";
353 stream <<
" extent:\n";
356 stream <<
" east: " <<
bbox_.
east <<
"\n";
357 stream <<
" west: " <<
bbox_.
west <<
"\n";
358 stream <<
" resolution:\n";
359 stream <<
" ns: " <<
ns_res_ <<
"\n";
360 stream <<
" ew: " <<
ew_res_ <<
"\n";
361 stream <<
" raster:\n";
366 std::tie(min_row, min_col) =
368 std::tie(max_row, max_col) =
370 stream <<
" min_row: " << min_row <<
"\n";
371 stream <<
" min_col: " << min_col <<
"\n";
372 stream <<
" max_row: " << max_row <<
"\n";
373 stream <<
" max_col: " << max_col <<
"\n";
374 stream <<
" num_rows: " << max_row - min_row + 1 <<
"\n";
375 stream <<
" num_cols: " << max_col - min_col + 1 <<
"\n";
376 stream <<
" cost:\n";
378 std::set<std::pair<NodeId, NodeId>> edges;
380 for (
const auto& node_id : item.second) {
381 edges.emplace(item.first, node_id);
384 stream <<
" edges:\n";
385 for (
const auto& item : edges) {
386 stream <<
" - [" << item.first <<
", " << item.second <<
"]\n";
388 stream <<
" nodes:\n";
390 auto row = item.first.first;
391 auto col = item.first.second;
392 for (
const auto& node_id : item.second) {
393 stream <<
" - id: " << node_id <<
"\n";
394 stream <<
" row: " << row <<
"\n";
395 stream <<
" col: " << col <<
"\n";
398 stream <<
" segments:\n";
400 stream <<
" - start_node: " << item.first.first <<
"\n";
401 stream <<
" end_node: " << item.first.second <<
"\n";
402 stream <<
" cells: [";
403 for (
const auto& cell : item.second) {
404 stream <<
"[" << cell.first <<
", " << cell.second <<
"], ";
414 using Segment = std::vector<std::pair<RasterIndex, RasterIndex>>;
426 return std::stoi(text);
436 template<
typename Container>
441 : is_forward_(true), forward_it_(it)
444 : is_forward_(false), reverse_it_(it)
463 return forward_it_ != other.forward_it_;
464 return reverse_it_ != other.reverse_it_;
470 typename Container::const_iterator forward_it_;
471 typename Container::const_reverse_iterator reverse_it_;
485 typename Segment::const_iterator first,
486 typename Segment::const_iterator last)
487 : begin_(first), end_(last)
490 typename Segment::const_reverse_iterator first,
491 typename Segment::const_reverse_iterator last)
492 : begin_(first), end_(last)
514 template<
typename InputStream>
515 void load_nodes(InputStream& stream, std::set<NodeId>& node_ids)
518 while (std::getline(stream, line)) {
519 std::istringstream line_stream{line};
521 std::string node_text;
522 std::getline(line_stream, node_text, delimeter);
523 std::string x_coord_text;
524 std::getline(line_stream, x_coord_text, delimeter);
525 std::string y_coord_text;
526 std::getline(line_stream, y_coord_text, delimeter);
529 double x = std::stod(x_coord_text);
530 double y = std::stod(y_coord_text);
534 std::tie(row, col) =
xy_to_row_col(x_coord_text, y_coord_text);
537 std::runtime_error(
"Node ID must be greater than zero");
540 node_ids.insert(node_id);
550 template<
typename InputStream>
553 std::set<std::pair<NodeId, NodeId>> node_pairs;
555 while (std::getline(stream, line)) {
556 std::istringstream line_stream{line};
558 std::string node_1_text;
559 std::getline(line_stream, node_1_text, delimeter);
560 std::string node_2_text;
561 std::getline(line_stream, node_2_text, delimeter);
569 if (node_ids.find(node_1_id) == node_ids.end()
570 || node_ids.find(node_2_id) == node_ids.end())
572 if (node_1_id == node_2_id) {
574 std::string(
"Segment cannot begin and end with the same node: ")
575 + node_1_text +
" " + node_2_text);
577 std::string segment_text;
578 std::getline(line_stream, segment_text, delimeter);
582 node_pairs.emplace(node_1_id, node_2_id);
583 std::istringstream segment_stream{segment_text};
584 char in_cell_delimeter{
';'};
585 std::string x_coord_text;
586 std::string y_coord_text;
588 while (std::getline(segment_stream, x_coord_text, in_cell_delimeter)
589 && std::getline(segment_stream, y_coord_text, in_cell_delimeter)) {
594 if (segment.empty() || segment.back() != new_point)
595 segment.emplace_back(new_point);
598 std::make_pair(node_1_id, node_2_id), std::move(segment));
601 for (
auto node_id : node_ids) {
602 std::vector<NodeId> nodes;
603 for (
const auto& item : node_pairs) {
604 if (item.first == node_id)
605 nodes.push_back(item.second);
606 else if (item.second == node_id)
607 nodes.push_back(item.first);
627 const auto& key{item.first};
628 if (key.first == start && key.second == end)
629 return SegmentView(item.second.cbegin(), item.second.cend());
630 if (key.second == start && key.first == end) {
631 return SegmentView(item.second.crbegin(), item.second.crend());
634 throw std::invalid_argument(
"No segment for given nodes");
662 template<
typename Generator>
670 auto num_nodes = all_nodes.size();
673 else if (num_nodes == 1)
677 std::vector<int> nodes;
678 std::back_insert_iterator<std::vector<int>> back_it(nodes);
680 all_nodes.begin(), all_nodes.end(), back_it, [&ignore](
NodeId id) {
681 return container_contains(ignore, id);
685 num_nodes = nodes.size();
688 else if (num_nodes == 1)
696 template<
typename Container,
typename Generator>
699 auto num_nodes = nodes.size();
700 std::uniform_int_distribution<size_t> dist(0, num_nodes - 1);
701 auto index = dist(generator);
704 return *std::next(nodes.begin(), index);
724 template<
typename RasterIndex>
752 template<
typename Generator>
753 std::tuple<int, int>
operator()(Generator& generator,
int row,
int col)
756 std::tie(row, col) =
network_.travel(row, col, time, generator);
758 return std::make_tuple(row, col);
770 return network_.has_node_at(row, col);
789 #endif // POPS_NETWORK_KERNEL_HPP