From d4f3b56b6f3f765c3a8897ea895046f35cafd1eb Mon Sep 17 00:00:00 2001 From: eric bryant Date: Sun, 31 Mar 2019 13:45:52 -0400 Subject: [PATCH 01/17] C++: rename classes/functions/variables in preparation for "traveled" graph implementation --- .../classes/GraphGeneration/HighwayGraph.cpp | 180 +++++++++--------- .../HighwayGraphCollapsedEdgeInfo.cpp | 68 +++---- .../HighwayGraphCollapsedEdgeInfo.h | 12 +- .../GraphGeneration/HighwayGraphEdgeInfo.cpp | 20 +- .../GraphGeneration/HighwayGraphEdgeInfo.h | 2 +- .../HighwayGraphVertexInfo.cpp | 26 +-- .../classes/GraphGeneration/PlaceRadius.cpp | 14 +- .../cplusplus/classes/HighwaySystem.cpp | 2 +- siteupdate/cplusplus/classes/Region.cpp | 2 +- siteupdate/cplusplus/siteupdate.cpp | 4 +- 10 files changed, 165 insertions(+), 165 deletions(-) diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp index 9ab3db1f..9d872511 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp @@ -15,7 +15,7 @@ class HighwayGraph // to track the waypoint name compressions, add log entries // to this list std::list waypoint_naming_log; - std::unordered_map vertices; + std::unordered_map vertices; HighwayGraph ( WaypointQuadtree &all_waypoints, @@ -70,14 +70,14 @@ class HighwayGraph // we're good; now construct a vertex if (!w->colocated) - vertices[w] = new HighwayGraphVertexInfo(w, &*(vertex_names.insert(point_name).first), datacheckerrors, numthreads); - else vertices[w] = new HighwayGraphVertexInfo(w->colocated->front(), &*(vertex_names.insert(point_name).first), datacheckerrors, numthreads); + vertices[w] = new HGVertex(w, &*(vertex_names.insert(point_name).first), datacheckerrors, numthreads); + else vertices[w] = new HGVertex(w->colocated->front(), &*(vertex_names.insert(point_name).first), datacheckerrors, numthreads); // vertices are deleted by HighwayGraph::clear } std::cout << '!' << std::endl; //#include "../../debug/unique_names.cpp" - // add edges, which end up in two separate vertex adjacency lists, + // create edges counter = 0; std::cout << et.et() << "Creating edges" << std::flush; for (HighwaySystem *h : highway_systems) @@ -92,81 +92,82 @@ class HighwayGraph HighwayGraphEdgeInfo *e = new HighwayGraphEdgeInfo(s, this, duplicate); // and again for a graph where hidden waypoints // are merged into the edge structures - if (!duplicate) new HighwayGraphCollapsedEdgeInfo(e); - // edges & collapsed edges are deleted by ~HighwayGraphVertexInfo, called by HighwayGraph::clear + if (!duplicate) new HGEdge(e); + // edges & collapsed edges are deleted by ~HGVertex, called by HighwayGraph::clear } } - std::cout << "!\n" << et.et() << "Full graph has " << vertices.size() << " vertices, " << edge_count() << " edges." << std::endl; + std::cout << "!\n" << et.et() << "Full graph has " << vertices.size() << " vertices, " << simple_edge_count() << " edges." << std::endl; // compress edges adjacent to hidden vertices counter = 0; std::cout << et.et() << "Compressing collapsed edges" << std::flush; - for (std::pair wv : vertices) + for (std::pair wv : vertices) { if (counter % 10000 == 0) std::cout << '.' << std::flush; counter++; if (wv.second->is_hidden) - { if (wv.second->incident_collapsed_edges.size() < 2) - { // these cases are flagged as HIDDEN_TERMINUS - wv.second->is_hidden = 0; + { // cases with only one edge are flagged as HIDDEN_TERMINUS + if (wv.second->incident_c_edges.size() < 2) + { wv.second->is_hidden = 0; continue; } - if (wv.second->incident_collapsed_edges.size() > 2) + // if >2 edges, flag HIDDEN_JUNCTION, mark as visible, and do not compress + if (wv.second->incident_c_edges.size() > 2) { std::list::iterator it = wv.second->first_waypoint->colocated->begin(); Waypoint *dcw = *it; // "datacheck waypoint" for (it++; it != wv.second->first_waypoint->colocated->end(); it++) if (dcw->root_at_label() > (*it)->root_at_label()) - dcw->root_at_label() = (*it)->root_at_label(); - datacheckerrors->add(dcw->route, dcw->label, "", "", "HIDDEN_JUNCTION", std::to_string(wv.second->incident_collapsed_edges.size())); + dcw->root_at_label() = (*it)->root_at_label(); //TODO: WHAT THE...? How is this actually working? (Or is it?) + datacheckerrors->add(dcw->route, dcw->label, "", "", "HIDDEN_JUNCTION", std::to_string(wv.second->incident_c_edges.size())); wv.second->is_hidden = 0; continue; } - // construct from vertex_info this time - new HighwayGraphCollapsedEdgeInfo(wv.second); - // collapsed edges are deleted by ~HighwayGraphVertexInfo, called by HighwayGraph::clear + // construct from vertex this time + new HGEdge(wv.second); + // collapsed edges are deleted by ~HGVertex, called by HighwayGraph::clear } } // print summary info - std::cout << "!\n" << et.et() << "Edge compressed graph has " << num_visible_vertices() + std::cout << "!\n" << et.et() << "Edge compressed graph has " << num_collapsed_vertices() << " vertices, " << collapsed_edge_count() << " edges." << std::endl; } // end ctor - unsigned int num_visible_vertices() + unsigned int num_collapsed_vertices() { unsigned int count = 0; - for (std::pair wv : vertices) + for (std::pair wv : vertices) if (!wv.second->is_hidden) count ++; return count; } - unsigned int edge_count() + unsigned int simple_edge_count() { unsigned int edges = 0; - for (std::pair wv : vertices) - edges += wv.second->incident_edges.size(); + for (std::pair wv : vertices) + edges += wv.second->incident_s_edges.size(); return edges/2; } unsigned int collapsed_edge_count() { unsigned int edges = 0; - for (std::pair wv : vertices) + for (std::pair wv : vertices) if (!wv.second->is_hidden) - edges += wv.second->incident_collapsed_edges.size(); + edges += wv.second->incident_c_edges.size(); return edges/2; } void clear() - { for (std::pair wv : vertices) delete wv.second; + { for (std::pair wv : vertices) delete wv.second; vertex_names.clear(); waypoint_naming_log.clear(); vertices.clear(); } - std::unordered_set matching_vertices(GraphListEntry &g, unsigned int &vis) - { // return a set of vertices from the graph, optionally - // restricted by region or system or placeradius area - vis = 0; - std::unordered_set vertex_set; - std::unordered_set rg_vertex_set; - std::unordered_set sys_vertex_set; + std::unordered_set matching_vertices(GraphListEntry &g, unsigned int &cv_count) + { // Return a set of vertices from the graph, optionally + // restricted by region or system or placeradius area. + cv_count = 0; + std::unordered_set vertex_set; + std::unordered_set rg_vertex_set; + std::unordered_set sys_vertex_set; // rg_vertex_set is the union of all sets in regions if (g.regions) for (Region *r : *g.regions) rg_vertex_set.insert(r->vertices.begin(), r->vertices.end()); @@ -180,34 +181,34 @@ class HighwayGraph if (g.systems) // both regions & systems populated: vertex_set is // intersection of rg_vertex_set & sys_vertex_set - for (HighwayGraphVertexInfo *v : sys_vertex_set) + for (HGVertex *v : sys_vertex_set) vertex_set.erase(v); } else if (g.systems) // only systems populated vertex_set = sys_vertex_set; else // neither are populated; include all vertices... - for (std::pair wv : vertices) + for (std::pair wv : vertices) // ...unless a PlaceRadius is specified - if (!g.placeradius || g.placeradius->contains_vertex_info(wv.second)) + if (!g.placeradius || g.placeradius->contains_vertex(wv.second)) vertex_set.insert(wv.second); // if placeradius is provided along with region or // system parameters, erase vertices outside placeradius if (g.placeradius && (g.systems || g.regions)) - { std::unordered_set::iterator v = vertex_set.begin(); + { std::unordered_set::iterator v = vertex_set.begin(); while(v != vertex_set.end()) - if (!g.placeradius->contains_vertex_info(*v)) + if (!g.placeradius->contains_vertex(*v)) v = vertex_set.erase(v); else v++; } - // find number of visible vertices - for (HighwayGraphVertexInfo *v : vertex_set) - if (!v->is_hidden) vis++; + // find number of collapsed vertices + for (HGVertex *v : vertex_set) + if (!v->is_hidden) cv_count++; return vertex_set; }//*/ - std::unordered_set matching_edges(std::unordered_set &mv, GraphListEntry &g) + std::unordered_set matching_simple_edges(std::unordered_set &mv, GraphListEntry &g) { // return a set of edges from the graph, optionally // restricted by region or system or placeradius area std::unordered_set edge_set; @@ -233,8 +234,8 @@ class HighwayGraph // only systems populated edge_set = sys_edge_set; else // neither are populated; include all edges/// - for (HighwayGraphVertexInfo *v : mv) - for (HighwayGraphEdgeInfo *e : v->incident_edges) + for (HGVertex *v : mv) + for (HighwayGraphEdgeInfo *e : v->incident_s_edges) // ...unless a PlaceRadius is specified if (!g.placeradius || g.placeradius->contains_edge(e)) edge_set.insert(e); @@ -251,14 +252,13 @@ class HighwayGraph return edge_set; } - std::unordered_set matching_collapsed_edges(std::unordered_set &mv, GraphListEntry &g) - { // return a set of edges from the graph edges for the collapsed - // edge format, optionally restricted by region or system or - // placeradius area - std::unordered_set edge_set; - for (HighwayGraphVertexInfo *v : mv) + std::unordered_set matching_collapsed_edges(std::unordered_set &mv, GraphListEntry &g) + { // return a set of edges for the collapsed edge graph format, + // optionally restricted by region or system or placeradius + std::unordered_set edge_set; + for (HGVertex *v : mv) { if (v->is_hidden) continue; - for (HighwayGraphCollapsedEdgeInfo *e : v->incident_collapsed_edges) + for (HGEdge *e : v->incident_c_edges) if (!g.placeradius || g.placeradius->contains_edge(e)) { bool rg_in_rg = 0; if (g.regions) for (Region *r : *g.regions) @@ -298,41 +298,41 @@ class HighwayGraph void write_master_tmg_simple(GraphListEntry *msptr, std::string filename) { std::ofstream tmgfile(filename.data()); tmgfile << "TMG 1.0 simple\n"; - tmgfile << vertices.size() << ' ' << edge_count() << '\n'; + tmgfile << vertices.size() << ' ' << simple_edge_count() << '\n'; // number waypoint entries as we go to support original .gra // format output - int vertex_num = 0; - for (std::pair wv : vertices) + int s_vertex_num = 0; + for (std::pair wv : vertices) { char fstr[42]; sprintf(fstr, "%.15g %.15g", wv.second->lat, wv.second->lng); tmgfile << *(wv.second->unique_name) << ' ' << fstr << '\n'; - wv.second->vertex_num[0] = vertex_num; - vertex_num++; + wv.second->s_vertex_num[0] = s_vertex_num; + s_vertex_num++; } // sanity check - if (vertices.size() != vertex_num) - std::cout << "ERROR: computed " << vertices.size() << " waypoints but wrote " << vertex_num << std::endl; + if (vertices.size() != s_vertex_num) + std::cout << "ERROR: computed " << vertices.size() << " waypoints but wrote " << s_vertex_num << std::endl; // now edges, only print if not already printed int edge = 0; - for (std::pair wv : vertices) - for (HighwayGraphEdgeInfo *e : wv.second->incident_edges) + for (std::pair wv : vertices) + for (HighwayGraphEdgeInfo *e : wv.second->incident_s_edges) if (!e->written) { e->written = 1; - tmgfile << e->vertex1->vertex_num[0] << ' ' << e->vertex2->vertex_num[0] << ' ' << e->label(0) << '\n'; + tmgfile << e->vertex1->s_vertex_num[0] << ' ' << e->vertex2->s_vertex_num[0] << ' ' << e->label(0) << '\n'; edge++; } // sanity checks - for (std::pair wv : vertices) - for (HighwayGraphEdgeInfo *e : wv.second->incident_edges) + for (std::pair wv : vertices) + for (HighwayGraphEdgeInfo *e : wv.second->incident_s_edges) if (!e->written) - std::cout << "ERROR: never wrote edge " << e->vertex1->vertex_num << ' ' << e->vertex2->vertex_num[0] << ' ' << e->label(0) << std::endl; - if (edge_count() != edge) - std::cout << "ERROR: computed " << edge_count() << " edges but wrote " << edge << std::endl; + std::cout << "ERROR: never wrote edge " << e->vertex1->s_vertex_num << ' ' << e->vertex2->s_vertex_num[0] << ' ' << e->label(0) << std::endl; + if (simple_edge_count() != edge) + std::cout << "ERROR: computed " << simple_edge_count() << " edges but wrote " << edge << std::endl; tmgfile.close(); msptr->vertices = vertices.size(); - msptr->edges = edge_count(); + msptr->edges = simple_edge_count(); } // write the entire set of data in the tmg collapsed edge format @@ -340,23 +340,23 @@ class HighwayGraph { std::ofstream tmgfile(filename.data()); unsigned int num_collapsed_edges = collapsed_edge_count(); tmgfile << "TMG 1.0 collapsed\n"; - tmgfile << num_visible_vertices() << " " << num_collapsed_edges << '\n'; + tmgfile << num_collapsed_vertices() << " " << num_collapsed_edges << '\n'; // write visible vertices - int vis_vertex_num = 0; - for (std::pair wv : vertices) + int c_vertex_num = 0; + for (std::pair wv : vertices) if (!wv.second->is_hidden) { char fstr[42]; sprintf(fstr, "%.15g %.15g", wv.second->lat, wv.second->lng); tmgfile << *(wv.second->unique_name) << ' ' << fstr << '\n'; - wv.second->vis_vertex_num[threadnum] = vis_vertex_num; - vis_vertex_num++; + wv.second->c_vertex_num[threadnum] = c_vertex_num; + c_vertex_num++; } // write collapsed edges int edge = 0; - for (std::pair wv : vertices) + for (std::pair wv : vertices) if (!wv.second->is_hidden) - for (HighwayGraphCollapsedEdgeInfo *e : wv.second->incident_collapsed_edges) + for (HGEdge *e : wv.second->incident_c_edges) if (!e->written) { e->written = 1; tmgfile << e->collapsed_tmg_line(0, threadnum) << '\n'; @@ -367,61 +367,61 @@ class HighwayGraph std::cout << "ERROR: computed " << num_collapsed_edges << " collapsed edges, but wrote " << edge << '\n'; tmgfile.close(); - mcptr->vertices = num_visible_vertices(); + mcptr->vertices = num_collapsed_vertices(); mcptr->edges = num_collapsed_edges; } // write a subset of the data, // in both simple and collapsed formats, // restricted by regions in the list if given, - // by system in the list if given, + // by systems in the list if given, // or to within a given area if placeradius is given void write_subgraphs_tmg(std::vector &graph_vector, std::string path, size_t graphnum, unsigned int threadnum) - { unsigned int visible_v; + { unsigned int cv_count; std::string simplefilename = path+graph_vector[graphnum].filename(); std::string collapfilename = path+graph_vector[graphnum+1].filename(); std::ofstream simplefile(simplefilename.data()); std::ofstream collapfile(collapfilename.data()); - std::unordered_set mv = matching_vertices(graph_vector[graphnum], visible_v); - std::unordered_set mse = matching_edges(mv, graph_vector[graphnum]); - std::unordered_set mce = matching_collapsed_edges(mv, graph_vector[graphnum]); + std::unordered_set mv = matching_vertices(graph_vector[graphnum], cv_count); + std::unordered_set mse = matching_simple_edges(mv, graph_vector[graphnum]); + std::unordered_set mce = matching_collapsed_edges(mv, graph_vector[graphnum]); std::cout << graph_vector[graphnum].tag() << '(' << mv.size() << ',' << mse.size() << ") " - << '(' << visible_v << ',' << mce.size() << ") " << std::flush; + << '(' << cv_count << ',' << mce.size() << ") " << std::flush; simplefile << "TMG 1.0 simple\n"; collapfile << "TMG 1.0 collapsed\n"; simplefile << mv.size() << ' ' << mse.size() << '\n'; - collapfile << visible_v << ' ' << mce.size() << '\n'; + collapfile << cv_count << ' ' << mce.size() << '\n'; // write vertices unsigned int sv = 0; unsigned int cv = 0; - for (HighwayGraphVertexInfo *v : mv) + for (HGVertex *v : mv) { char fstr[43]; sprintf(fstr, " %.15g %.15g", v->lat, v->lng); - // all vertices, for simple graph + // all vertices for simple graph simplefile << *(v->unique_name) << fstr << '\n'; - v->vertex_num[threadnum] = sv; + v->s_vertex_num[threadnum] = sv; sv++; // visible vertices, for collapsed graph if (!v->is_hidden) { collapfile << *(v->unique_name) << fstr << '\n'; - v->vis_vertex_num[threadnum] = cv; + v->c_vertex_num[threadnum] = cv; cv++; } } // write edges for (HighwayGraphEdgeInfo *e : mse) - simplefile << e->vertex1->vertex_num[threadnum] << ' ' - << e->vertex2->vertex_num[threadnum] << ' ' + simplefile << e->vertex1->s_vertex_num[threadnum] << ' ' + << e->vertex2->s_vertex_num[threadnum] << ' ' << e->label(graph_vector[graphnum].systems) << '\n'; - for (HighwayGraphCollapsedEdgeInfo *e : mce) + for (HGEdge *e : mce) collapfile << e->collapsed_tmg_line(graph_vector[graphnum].systems, threadnum) << '\n'; simplefile.close(); collapfile.close(); graph_vector[graphnum].vertices = mv.size(); - graph_vector[graphnum+1].vertices = visible_v; + graph_vector[graphnum+1].vertices = cv_count; graph_vector[graphnum].edges = mse.size(); graph_vector[graphnum+1].edges = mce.size(); } diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphCollapsedEdgeInfo.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphCollapsedEdgeInfo.cpp index 4ef85d99..ef65003b 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphCollapsedEdgeInfo.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphCollapsedEdgeInfo.cpp @@ -1,4 +1,4 @@ -HighwayGraphCollapsedEdgeInfo::HighwayGraphCollapsedEdgeInfo(HighwayGraphEdgeInfo *e) +HGEdge::HGEdge(HighwayGraphEdgeInfo *e) { // initial construction is based on a HighwayGraphEdgeInfo written = 0; segment_name = e->segment_name; @@ -10,29 +10,29 @@ HighwayGraphCollapsedEdgeInfo::HighwayGraphCollapsedEdgeInfo(HighwayGraphEdgeInf region = e->region; // a list of route name/system pairs route_names_and_systems = e->route_names_and_systems; - vertex1->incident_collapsed_edges.push_back(this); - vertex2->incident_collapsed_edges.push_back(this); + vertex1->incident_c_edges.push_back(this); + vertex2->incident_c_edges.push_back(this); } -HighwayGraphCollapsedEdgeInfo::HighwayGraphCollapsedEdgeInfo(HighwayGraphVertexInfo *vertex_info) +HGEdge::HGEdge(HGVertex *vertex) { // build by collapsing two existing edges around a common // hidden vertex waypoint, whose information is given in - // vertex_info + // vertex written = 0; // we know there are exactly 2 incident edges, as we // checked for that, and we will replace these two // with the single edge we are constructing here - HighwayGraphCollapsedEdgeInfo *edge1 = vertex_info->incident_collapsed_edges.front(); - HighwayGraphCollapsedEdgeInfo *edge2 = vertex_info->incident_collapsed_edges.back(); + HGEdge *edge1 = vertex->incident_c_edges.front(); + HGEdge *edge2 = vertex->incident_c_edges.back(); // segment names should match as routes should not start or end // nor should concurrencies begin or end at a hidden point if (edge1->segment_name != edge2->segment_name) - { std::cout << "ERROR: segment name mismatch in HighwayGraphCollapsedEdgeInfo: "; + { std::cout << "ERROR: segment name mismatch in HGEdge collapse constructor: "; std::cout << "edge1 named " << edge1->segment_name << " edge2 named " << edge2->segment_name << '\n' << std::endl; } segment_name = edge1->segment_name; //std::cout << "\nDEBUG: collapsing edges along " << segment_name << " at vertex " << \ - *(vertex_info->unique_name) << ", edge1 is " << edge1->str() << " and edge2 is " << edge2->str() << std::endl; + *(vertex->unique_name) << ", edge1 is " << edge1->str() << " and edge2 is " << edge2->str() << std::endl; // region and route names/systems should also match, but not // doing that sanity check here, as the above check should take // care of that @@ -46,7 +46,7 @@ HighwayGraphCollapsedEdgeInfo::HighwayGraphCollapsedEdgeInfo(HighwayGraphVertexI intermediate_points = edge1->intermediate_points; //std::cout << "DEBUG: copied edge1 intermediates" << intermediate_point_string() << std::endl; - if (edge1->vertex1 == vertex_info) + if (edge1->vertex1 == vertex) { //std::cout << "DEBUG: vertex1 getting edge1->vertex2: " << *(edge1->vertex2->unique_name) << " and reversing edge1 intermediates" << std::endl; vertex1 = edge1->vertex2; intermediate_points.reverse(); @@ -55,10 +55,10 @@ HighwayGraphCollapsedEdgeInfo::HighwayGraphCollapsedEdgeInfo(HighwayGraphVertexI vertex1 = edge1->vertex1; } - //std::cout << "DEBUG: appending to intermediates: " << *(vertex_info->unique_name) << std::endl; - intermediate_points.push_back(vertex_info); + //std::cout << "DEBUG: appending to intermediates: " << *(vertex->unique_name) << std::endl; + intermediate_points.push_back(vertex); - if (edge2->vertex1 == vertex_info) + if (edge2->vertex1 == vertex) { //std::cout << "DEBUG: vertex2 getting edge2->vertex2: " << *(edge2->vertex2->unique_name) << std::endl; vertex2 = edge2->vertex2; } @@ -74,23 +74,23 @@ HighwayGraphCollapsedEdgeInfo::HighwayGraphCollapsedEdgeInfo(HighwayGraphVertexI // replace edge references at our endpoints with ourself delete edge1; // destructor removes edge from adjacency lists delete edge2; // destructor removes edge from adjacency lists - vertex1->incident_collapsed_edges.push_back(this); - vertex2->incident_collapsed_edges.push_back(this); + vertex1->incident_c_edges.push_back(this); + vertex2->incident_c_edges.push_back(this); } -HighwayGraphCollapsedEdgeInfo::~HighwayGraphCollapsedEdgeInfo() -{ for ( std::list::iterator e = vertex1->incident_collapsed_edges.begin(); - e != vertex1->incident_collapsed_edges.end(); +HGEdge::~HGEdge() +{ for ( std::list::iterator e = vertex1->incident_c_edges.begin(); + e != vertex1->incident_c_edges.end(); e++ ) if (*e == this) - { vertex1->incident_collapsed_edges.erase(e); + { vertex1->incident_c_edges.erase(e); break; } - for ( std::list::iterator e = vertex2->incident_collapsed_edges.begin(); - e != vertex2->incident_collapsed_edges.end(); + for ( std::list::iterator e = vertex2->incident_c_edges.begin(); + e != vertex2->incident_c_edges.end(); e++ ) if (*e == this) - { vertex2->incident_collapsed_edges.erase(e); + { vertex2->incident_c_edges.erase(e); break; } segment_name.clear(); @@ -99,7 +99,7 @@ HighwayGraphCollapsedEdgeInfo::~HighwayGraphCollapsedEdgeInfo() } // compute an edge label, optionally resticted by systems -std::string HighwayGraphCollapsedEdgeInfo::label(std::list *systems) +std::string HGEdge::label(std::list *systems) { std::string the_label; for (std::pair &ns : route_names_and_systems) { // test whether system in systems @@ -118,10 +118,10 @@ std::string HighwayGraphCollapsedEdgeInfo::label(std::list *syst } // line appropriate for a tmg collapsed edge file -std::string HighwayGraphCollapsedEdgeInfo::collapsed_tmg_line(std::list *systems, unsigned int threadnum) -{ std::string line = std::to_string(vertex1->vis_vertex_num[threadnum]) + " " + std::to_string(vertex2->vis_vertex_num[threadnum]) + " " + label(systems); +std::string HGEdge::collapsed_tmg_line(std::list *systems, unsigned int threadnum) +{ std::string line = std::to_string(vertex1->c_vertex_num[threadnum]) + " " + std::to_string(vertex2->c_vertex_num[threadnum]) + " " + label(systems); char fstr[43]; - for (HighwayGraphVertexInfo *intermediate : intermediate_points) + for (HGVertex *intermediate : intermediate_points) { sprintf(fstr, " %.15g %.15g", intermediate->lat, intermediate->lng); line += fstr; } @@ -129,11 +129,11 @@ std::string HighwayGraphCollapsedEdgeInfo::collapsed_tmg_line(std::list *systems, unsigned int threadnum) -{ std::string line = std::to_string(vertex1->vis_vertex_num[threadnum]) + " [" + *vertex1->unique_name + "] " \ - + std::to_string(vertex2->vis_vertex_num[threadnum]) + " [" + *vertex2->unique_name + "] " + label(systems); +std::string HGEdge::debug_tmg_line(std::list *systems, unsigned int threadnum) +{ std::string line = std::to_string(vertex1->c_vertex_num[threadnum]) + " [" + *vertex1->unique_name + "] " \ + + std::to_string(vertex2->c_vertex_num[threadnum]) + " [" + *vertex2->unique_name + "] " + label(systems); char fstr[44]; - for (HighwayGraphVertexInfo *intermediate : intermediate_points) + for (HGVertex *intermediate : intermediate_points) { sprintf(fstr, "] %.15g %.15g", intermediate->lat, intermediate->lng); line += " [" + *intermediate->unique_name + fstr; } @@ -141,19 +141,19 @@ std::string HighwayGraphCollapsedEdgeInfo::debug_tmg_line(std::listunique_name + " to " + *vertex2->unique_name + " via " + std::to_string(intermediate_points.size()) + " points"; } // return the intermediate points as a string -std::string HighwayGraphCollapsedEdgeInfo::intermediate_point_string() +std::string HGEdge::intermediate_point_string() { if (intermediate_points.empty()) return " None"; std::string line = ""; char fstr[42]; - for (HighwayGraphVertexInfo *i : intermediate_points) + for (HGVertex *i : intermediate_points) { sprintf(fstr, "%.15g %.15g", i->lat, i->lng); line += " [" + *i->unique_name + "] " + fstr; } diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphCollapsedEdgeInfo.h b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphCollapsedEdgeInfo.h index 8534f1a2..17544227 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphCollapsedEdgeInfo.h +++ b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphCollapsedEdgeInfo.h @@ -1,18 +1,18 @@ -class HighwayGraphCollapsedEdgeInfo +class HGEdge { /* This class encapsulates information needed for a highway graph edge that can incorporate intermediate points. */ public: bool written; std::string segment_name; - HighwayGraphVertexInfo *vertex1, *vertex2; - std::list intermediate_points; // if more than 1, will go from vertex1 to vertex2 + HGVertex *vertex1, *vertex2; + std::list intermediate_points; // if more than 1, will go from vertex1 to vertex2 Region *region; std::list> route_names_and_systems; - HighwayGraphCollapsedEdgeInfo(HighwayGraphEdgeInfo *); - HighwayGraphCollapsedEdgeInfo(HighwayGraphVertexInfo *); - ~HighwayGraphCollapsedEdgeInfo(); + HGEdge(HighwayGraphEdgeInfo *); + HGEdge(HGVertex *); + ~HGEdge(); std::string label(std::list *); std::string collapsed_tmg_line(std::list *, unsigned int); diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphEdgeInfo.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphEdgeInfo.cpp index 61ac8ce9..5ae646de 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphEdgeInfo.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphEdgeInfo.cpp @@ -6,16 +6,16 @@ HighwayGraphEdgeInfo::HighwayGraphEdgeInfo(HighwaySegment *s, HighwayGraph *grap vertex2 = graph->vertices.at(s->waypoint2->hashpoint()); // checks for the very unusual cases where an edge ends up // in the system as itself and its "reverse" - for (HighwayGraphEdgeInfo *e : vertex1->incident_edges) + for (HighwayGraphEdgeInfo *e : vertex1->incident_s_edges) if (e->vertex1 == vertex2 && e->vertex2 == vertex1) duplicate = 1; - for (HighwayGraphEdgeInfo *e : vertex2->incident_edges) + for (HighwayGraphEdgeInfo *e : vertex2->incident_s_edges) if (e->vertex1 == vertex2 && e->vertex2 == vertex1) duplicate = 1; if (duplicate) { delete this; return; } - vertex1->incident_edges.push_back(this); - vertex2->incident_edges.push_back(this); + vertex1->incident_s_edges.push_back(this); + vertex2->incident_s_edges.push_back(this); // assumption: each edge/segment lives within a unique region region = s->route->region; region->edges.insert(this); @@ -32,18 +32,18 @@ HighwayGraphEdgeInfo::HighwayGraphEdgeInfo(HighwaySegment *s, HighwayGraph *grap } HighwayGraphEdgeInfo::~HighwayGraphEdgeInfo() -{ for ( std::list::iterator e = vertex1->incident_edges.begin(); - e != vertex1->incident_edges.end(); +{ for ( std::list::iterator e = vertex1->incident_s_edges.begin(); + e != vertex1->incident_s_edges.end(); e++ ) if (*e == this) - { vertex1->incident_edges.erase(e); + { vertex1->incident_s_edges.erase(e); break; } - for ( std::list::iterator e = vertex2->incident_edges.begin(); - e != vertex2->incident_edges.end(); + for ( std::list::iterator e = vertex2->incident_s_edges.begin(); + e != vertex2->incident_s_edges.end(); e++ ) if (*e == this) - { vertex2->incident_edges.erase(e); + { vertex2->incident_s_edges.erase(e); break; } segment_name.clear(); diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphEdgeInfo.h b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphEdgeInfo.h index 4a1b7e02..0e339062 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphEdgeInfo.h +++ b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphEdgeInfo.h @@ -5,7 +5,7 @@ class HighwayGraphEdgeInfo public: bool written; std::string segment_name; - HighwayGraphVertexInfo *vertex1, *vertex2; + HGVertex *vertex1, *vertex2; Region *region; std::list> route_names_and_systems; diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphVertexInfo.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphVertexInfo.cpp index 62feb11a..e3d975be 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphVertexInfo.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphVertexInfo.cpp @@ -1,4 +1,4 @@ -class HighwayGraphVertexInfo +class HGVertex { /* This class encapsulates information needed for a highway graph vertex. */ @@ -9,16 +9,16 @@ class HighwayGraphVertexInfo Waypoint *first_waypoint; std::unordered_set regions; std::unordered_set systems; - std::list incident_edges; - std::list incident_collapsed_edges; - int *vertex_num; - int *vis_vertex_num; + std::list incident_s_edges; + std::list incident_c_edges; + int *s_vertex_num; + int *c_vertex_num; - HighwayGraphVertexInfo(Waypoint *wpt, const std::string *n, DatacheckEntryList *datacheckerrors, unsigned int numthreads) + HGVertex(Waypoint *wpt, const std::string *n, DatacheckEntryList *datacheckerrors, unsigned int numthreads) { lat = wpt->lat; lng = wpt->lng; - vertex_num = new int[numthreads]; - vis_vertex_num = new int[numthreads]; + s_vertex_num = new int[numthreads]; + c_vertex_num = new int[numthreads]; unique_name = n; // will consider hidden iff all colocated waypoints are hidden is_hidden = 1; @@ -57,12 +57,12 @@ class HighwayGraphVertexInfo } } - ~HighwayGraphVertexInfo() + ~HGVertex() { //std::cout << "deleting vertex at " << first_waypoint->str() << std::endl; - while (incident_edges.size()) delete incident_edges.front(); - while (incident_collapsed_edges.size()) delete incident_collapsed_edges.front(); - delete[] vertex_num; - delete[] vis_vertex_num; + while (incident_s_edges.size()) delete incident_s_edges.front(); + while (incident_c_edges.size()) delete incident_c_edges.front(); + delete[] s_vertex_num; + delete[] c_vertex_num; regions.clear(); systems.clear(); } diff --git a/siteupdate/cplusplus/classes/GraphGeneration/PlaceRadius.cpp b/siteupdate/cplusplus/classes/GraphGeneration/PlaceRadius.cpp index c8f7efb3..390e52dc 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/PlaceRadius.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/PlaceRadius.cpp @@ -19,13 +19,13 @@ class PlaceRadius r = strtoul(R, 0, 10); } - bool contains_vertex_info(HighwayGraphVertexInfo *vinfo) - { /* return whether vinfo's coordinates are within this area */ + bool contains_vertex(HGVertex *v) + { /* return whether v's coordinates are within this area */ // convert to radians to compute distance double rlat1 = lat * Waypoint::pi/180; double rlng1 = lng * Waypoint::pi/180; - double rlat2 = vinfo->lat * Waypoint::pi/180; - double rlng2 = vinfo->lng * Waypoint::pi/180; + double rlat2 = v->lat * Waypoint::pi/180; + double rlng2 = v->lng * Waypoint::pi/180; double ans = acos(cos(rlat1)*cos(rlng1)*cos(rlat2)*cos(rlng2) +\ cos(rlat1)*sin(rlng1)*cos(rlat2)*sin(rlng2) +\ @@ -35,11 +35,11 @@ class PlaceRadius bool contains_edge(HighwayGraphEdgeInfo *e) { /* return whether both endpoints of edge e are within this area */ - return contains_vertex_info(e->vertex1) and contains_vertex_info(e->vertex2); + return contains_vertex(e->vertex1) and contains_vertex(e->vertex2); } - bool contains_edge(HighwayGraphCollapsedEdgeInfo *e) + bool contains_edge(HGEdge *e) { /* return whether both endpoints of edge e are within this area */ - return contains_vertex_info(e->vertex1) and contains_vertex_info(e->vertex2); + return contains_vertex(e->vertex1) and contains_vertex(e->vertex2); } }; diff --git a/siteupdate/cplusplus/classes/HighwaySystem.cpp b/siteupdate/cplusplus/classes/HighwaySystem.cpp index b27314f1..8efba9ce 100644 --- a/siteupdate/cplusplus/classes/HighwaySystem.cpp +++ b/siteupdate/cplusplus/classes/HighwaySystem.cpp @@ -27,7 +27,7 @@ class HighwaySystem std::list route_list; std::list con_route_list; std::unordered_map mileage_by_region; - std::unordered_set vertices; + std::unordered_set vertices; std::unordered_set edges; HighwaySystem(std::string &line, ErrorList &el, std::string path, std::string &systemsfile, diff --git a/siteupdate/cplusplus/classes/Region.cpp b/siteupdate/cplusplus/classes/Region.cpp index 31425dc6..c4919396 100644 --- a/siteupdate/cplusplus/classes/Region.cpp +++ b/siteupdate/cplusplus/classes/Region.cpp @@ -40,7 +40,7 @@ class Region double active_preview_mileage; double overall_mileage; std::mutex *ao_mi_mtx, *ap_mi_mtx, *ov_mi_mtx; - std::unordered_set vertices; + std::unordered_set vertices; std::unordered_set edges; Region (std::string &line, diff --git a/siteupdate/cplusplus/siteupdate.cpp b/siteupdate/cplusplus/siteupdate.cpp index 930964f8..db1e39c3 100644 --- a/siteupdate/cplusplus/siteupdate.cpp +++ b/siteupdate/cplusplus/siteupdate.cpp @@ -23,9 +23,9 @@ class TravelerList; class Region; class DatacheckEntryList; class HighwayGraph; -class HighwayGraphVertexInfo; +class HGVertex; class HighwayGraphEdgeInfo; -class HighwayGraphCollapsedEdgeInfo; +class HGEdge; #include #include #include From 74f729fb2bf47a6cf9c0a8098a38aafeb688ed66 Mon Sep 17 00:00:00 2001 From: eric bryant Date: Sun, 31 Mar 2019 15:20:00 -0400 Subject: [PATCH 02/17] C++: rename graph gen class files --- .../{HighwayGraphCollapsedEdgeInfo.cpp => HGEdge.cpp} | 0 .../{HighwayGraphCollapsedEdgeInfo.h => HGEdge.h} | 0 .../{HighwayGraphVertexInfo.cpp => HGVertex.cpp} | 0 siteupdate/cplusplus/siteupdate.cpp | 6 +++--- 4 files changed, 3 insertions(+), 3 deletions(-) rename siteupdate/cplusplus/classes/GraphGeneration/{HighwayGraphCollapsedEdgeInfo.cpp => HGEdge.cpp} (100%) rename siteupdate/cplusplus/classes/GraphGeneration/{HighwayGraphCollapsedEdgeInfo.h => HGEdge.h} (100%) rename siteupdate/cplusplus/classes/GraphGeneration/{HighwayGraphVertexInfo.cpp => HGVertex.cpp} (100%) diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphCollapsedEdgeInfo.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp similarity index 100% rename from siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphCollapsedEdgeInfo.cpp rename to siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphCollapsedEdgeInfo.h b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h similarity index 100% rename from siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphCollapsedEdgeInfo.h rename to siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphVertexInfo.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.cpp similarity index 100% rename from siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphVertexInfo.cpp rename to siteupdate/cplusplus/classes/GraphGeneration/HGVertex.cpp diff --git a/siteupdate/cplusplus/siteupdate.cpp b/siteupdate/cplusplus/siteupdate.cpp index db1e39c3..1959d1e8 100644 --- a/siteupdate/cplusplus/siteupdate.cpp +++ b/siteupdate/cplusplus/siteupdate.cpp @@ -70,13 +70,13 @@ class HGEdge; #include "classes/TravelerList/TravelerList.cpp" #include "classes/HighwaySegment/HighwaySegment.cpp" #include "classes/GraphGeneration/HighwayGraphEdgeInfo.h" -#include "classes/GraphGeneration/HighwayGraphCollapsedEdgeInfo.h" -#include "classes/GraphGeneration/HighwayGraphVertexInfo.cpp" +#include "classes/GraphGeneration/HGEdge.h" +#include "classes/GraphGeneration/HGVertex.cpp" #include "classes/GraphGeneration/PlaceRadius.cpp" #include "classes/GraphGeneration/GraphListEntry.cpp" #include "classes/GraphGeneration/HighwayGraph.cpp" #include "classes/GraphGeneration/HighwayGraphEdgeInfo.cpp" -#include "classes/GraphGeneration/HighwayGraphCollapsedEdgeInfo.cpp" +#include "classes/GraphGeneration/HGEdge.cpp" #include "threads/ReadWptThread.cpp" #include "threads/NmpMergedThread.cpp" #include "threads/ReadListThread.cpp" From cb0288bb8216832487807b7012de275d5253a761 Mon Sep 17 00:00:00 2001 From: eric bryant Date: Mon, 1 Apr 2019 20:27:04 -0400 Subject: [PATCH 03/17] C++: use one class for simple & collapsed edges --- .../classes/GraphGeneration/HGEdge.cpp | 122 +++++++++++++----- .../classes/GraphGeneration/HGEdge.h | 13 +- .../classes/GraphGeneration/HGVertex.cpp | 3 +- .../classes/GraphGeneration/HighwayGraph.cpp | 53 ++++---- .../classes/GraphGeneration/PlaceRadius.cpp | 5 - .../cplusplus/classes/HighwaySystem.cpp | 2 +- siteupdate/cplusplus/classes/Region.cpp | 3 +- .../cplusplus/classes/Route/read_wpt.cpp | 4 + .../WaypointQuadtree/WaypointQuadtree.cpp | 1 + .../cplusplus/functions/graph_generation.cpp | 6 + siteupdate/cplusplus/siteupdate.cpp | 7 +- .../cplusplus/threads/ReadListThread.cpp | 1 + 12 files changed, 146 insertions(+), 74 deletions(-) diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp index ef65003b..640eb9eb 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp @@ -1,24 +1,55 @@ -HGEdge::HGEdge(HighwayGraphEdgeInfo *e) -{ // initial construction is based on a HighwayGraphEdgeInfo - written = 0; - segment_name = e->segment_name; - vertex1 = e->vertex1; - vertex2 = e->vertex2; +// constants for more human-readable format masks +const unsigned char HGEdge::simple = 1; +const unsigned char HGEdge::collapsed = 2; +const unsigned char HGEdge::traveled = 4; + +HGEdge::HGEdge(HighwaySegment *s, HighwayGraph *graph) +{ // temp debug + s_written = 0; // simple + c_written = 0; // collapsed + vertex1 = graph->vertices.at(s->waypoint1->hashpoint()); + vertex2 = graph->vertices.at(s->waypoint2->hashpoint()); + // checks for the very unusual cases where an edge ends up + // in the system as itself and its "reverse" + for (HGEdge *e : vertex1->incident_s_edges) + if (e->vertex1 == vertex2 && e->vertex2 == vertex1) + { delete this; + return; + } + for (HGEdge *e : vertex2->incident_s_edges) + if (e->vertex1 == vertex2 && e->vertex2 == vertex1) + { delete this; + return; + } + format = simple | collapsed; + segment_name = s->segment_name(); + vertex1->incident_s_edges.push_back(this); + vertex2->incident_s_edges.push_back(this); + vertex1->incident_c_edges.push_back(this); + vertex2->incident_c_edges.push_back(this); // assumption: each edge/segment lives within a unique region // and a 'multi-edge' would not be able to span regions as there // would be a required visible waypoint at the border - region = e->region; + region = s->route->region; + region->edges.insert(this); // a list of route name/system pairs - route_names_and_systems = e->route_names_and_systems; - vertex1->incident_c_edges.push_back(this); - vertex2->incident_c_edges.push_back(this); + if (!s->concurrent) + { route_names_and_systems.emplace_back(s->route->list_entry_name(), s->route->system); + s->route->system->edges.insert(this); + } + else for (HighwaySegment *cs : *(s->concurrent)) + { if (cs->route->system->devel()) continue; + route_names_and_systems.emplace_back(cs->route->list_entry_name(), cs->route->system); + cs->route->system->edges.insert(this); + } } -HGEdge::HGEdge(HGVertex *vertex) +HGEdge::HGEdge(HGVertex *vertex, unsigned char fmt_mask) { // build by collapsing two existing edges around a common // hidden vertex waypoint, whose information is given in // vertex - written = 0; + c_written = 0; + format = fmt_mask; // we know there are exactly 2 incident edges, as we // checked for that, and we will replace these two // with the single edge we are constructing here @@ -68,31 +99,62 @@ HGEdge::HGEdge(HGVertex *vertex) } intermediate_points.splice(intermediate_points.end(), edge2->intermediate_points); - //std::cout << "DEBUG: intermediates complete: from " << *(vertex1->unique_name) << " via " \ - << intermediate_point_string() << " to " << *(vertex2->unique_name) << std::endl; + //std::cout << "DEBUG: intermediates complete: from " << *(vertex1->unique_name) << " via " << \ + intermediate_point_string() << " to " << *(vertex2->unique_name) << std::endl; // replace edge references at our endpoints with ourself - delete edge1; // destructor removes edge from adjacency lists - delete edge2; // destructor removes edge from adjacency lists + edge1->detach(fmt_mask); + edge2->detach(fmt_mask); + if (!edge1->format) delete edge1; + if (!edge2->format) delete edge2; vertex1->incident_c_edges.push_back(this); vertex2->incident_c_edges.push_back(this); } +void HGEdge::detach(unsigned char fmt_mask) +{ if (fmt_mask & simple) + { for ( std::list::iterator e = vertex1->incident_s_edges.begin(); + e != vertex1->incident_s_edges.end(); + e++ + ) if (*e == this) + { vertex1->incident_s_edges.erase(e); + break; + } + for ( std::list::iterator e = vertex2->incident_s_edges.begin(); + e != vertex2->incident_s_edges.end(); + e++ + ) if (*e == this) + { vertex2->incident_s_edges.erase(e); + break; + } + } + if (fmt_mask & collapsed) + { for ( std::list::iterator e = vertex1->incident_c_edges.begin(); + e != vertex1->incident_c_edges.end(); + e++ + ) if (*e == this) + { vertex1->incident_c_edges.erase(e); + break; + } + for ( std::list::iterator e = vertex2->incident_c_edges.begin(); + e != vertex2->incident_c_edges.end(); + e++ + ) if (*e == this) + { vertex2->incident_c_edges.erase(e); + break; + } + } + format &= ~fmt_mask; +} + HGEdge::~HGEdge() -{ for ( std::list::iterator e = vertex1->incident_c_edges.begin(); - e != vertex1->incident_c_edges.end(); - e++ - ) if (*e == this) - { vertex1->incident_c_edges.erase(e); - break; - } - for ( std::list::iterator e = vertex2->incident_c_edges.begin(); - e != vertex2->incident_c_edges.end(); - e++ - ) if (*e == this) - { vertex2->incident_c_edges.erase(e); - break; - } +{ /*if (format) + { std::cout << '~'; + if (format & simple) std::cout << 's'; + if (format & collapsed) std::cout << 'c'; + std::cout << std::endl; + }//*/ + detach(format); segment_name.clear(); intermediate_points.clear(); route_names_and_systems.clear(); diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h index 17544227..fc36b438 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h +++ b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h @@ -3,17 +3,24 @@ class HGEdge edge that can incorporate intermediate points. */ public: - bool written; + bool s_written, c_written; // simple, collapsed std::string segment_name; HGVertex *vertex1, *vertex2; std::list intermediate_points; // if more than 1, will go from vertex1 to vertex2 Region *region; std::list> route_names_and_systems; + unsigned char format; - HGEdge(HighwayGraphEdgeInfo *); - HGEdge(HGVertex *); + // constants for more human-readable format masks + static const unsigned char simple; + static const unsigned char collapsed; + static const unsigned char traveled; + + HGEdge(HighwaySegment *, HighwayGraph *); + HGEdge(HGVertex *, unsigned char); ~HGEdge(); + void detach(unsigned char); std::string label(std::list *); std::string collapsed_tmg_line(std::list *, unsigned int); std::string debug_tmg_line(std::list *, unsigned int); diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.cpp index e3d975be..868eec71 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.cpp @@ -9,7 +9,7 @@ class HGVertex Waypoint *first_waypoint; std::unordered_set regions; std::unordered_set systems; - std::list incident_s_edges; + std::list incident_s_edges; std::list incident_c_edges; int *s_vertex_num; int *c_vertex_num; @@ -19,6 +19,7 @@ class HGVertex lng = wpt->lng; s_vertex_num = new int[numthreads]; c_vertex_num = new int[numthreads]; + // deleted by ~HGVertex, called by HighwayGraph::clear unique_name = n; // will consider hidden iff all colocated waypoints are hidden is_hidden = 1; diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp index 9d872511..3d47a421 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp @@ -72,7 +72,7 @@ class HighwayGraph if (!w->colocated) vertices[w] = new HGVertex(w, &*(vertex_names.insert(point_name).first), datacheckerrors, numthreads); else vertices[w] = new HGVertex(w->colocated->front(), &*(vertex_names.insert(point_name).first), datacheckerrors, numthreads); - // vertices are deleted by HighwayGraph::clear + // deleted by HighwayGraph::clear } std::cout << '!' << std::endl; //#include "../../debug/unique_names.cpp" @@ -87,14 +87,8 @@ class HighwayGraph for (Route &r : h->route_list) for (HighwaySegment *s : r.segment_list) if (!s->concurrent || s == s->concurrent->front()) - { // first one copy for the full simple graph - bool duplicate = 0; - HighwayGraphEdgeInfo *e = new HighwayGraphEdgeInfo(s, this, duplicate); - // and again for a graph where hidden waypoints - // are merged into the edge structures - if (!duplicate) new HGEdge(e); - // edges & collapsed edges are deleted by ~HGVertex, called by HighwayGraph::clear - } + new HGEdge(s, this); + // deleted by ~HGVertex, called by HighwayGraph::clear } std::cout << "!\n" << et.et() << "Full graph has " << vertices.size() << " vertices, " << simple_edge_count() << " edges." << std::endl; @@ -122,8 +116,10 @@ class HighwayGraph continue; } // construct from vertex this time - new HGEdge(wv.second); - // collapsed edges are deleted by ~HGVertex, called by HighwayGraph::clear + new HGEdge(wv.second, HGEdge::collapsed); + // Final collapsed edges are deleted by ~HGVertex, called by HighwayGraph::clear. + // Partially collapsed edges created during the compression process are deleted + // upon detachment from all graphs. } } @@ -208,12 +204,12 @@ class HighwayGraph return vertex_set; }//*/ - std::unordered_set matching_simple_edges(std::unordered_set &mv, GraphListEntry &g) + std::unordered_set matching_simple_edges(std::unordered_set &mv, GraphListEntry &g) { // return a set of edges from the graph, optionally // restricted by region or system or placeradius area - std::unordered_set edge_set; - std::unordered_set rg_edge_set; - std::unordered_set sys_edge_set; + std::unordered_set edge_set; + std::unordered_set rg_edge_set; + std::unordered_set sys_edge_set; // rg_edge_set is the union of all sets in regions if (g.regions) for (Region *r : *g.regions) rg_edge_set.insert(r->edges.begin(), r->edges.end()); @@ -227,7 +223,7 @@ class HighwayGraph if (g.systems) // both regions & systems populated: edge_set is // intersection of rg_edge_set & sys_edge_set - for (HighwayGraphEdgeInfo *v : sys_edge_set) + for (HGEdge *v : sys_edge_set) edge_set.erase(v); } else if (g.systems) @@ -235,7 +231,7 @@ class HighwayGraph edge_set = sys_edge_set; else // neither are populated; include all edges/// for (HGVertex *v : mv) - for (HighwayGraphEdgeInfo *e : v->incident_s_edges) + for (HGEdge *e : v->incident_s_edges) // ...unless a PlaceRadius is specified if (!g.placeradius || g.placeradius->contains_edge(e)) edge_set.insert(e); @@ -243,7 +239,7 @@ class HighwayGraph // if placeradius is provided along with non-empty region // or system parameters, erase edges outside placeradius if (g.placeradius && (g.systems || g.regions)) - { std::unordered_set::iterator e = edge_set.begin(); + { std::unordered_set::iterator e = edge_set.begin(); while(e != edge_set.end()) if (!g.placeradius->contains_edge(*e)) e = edge_set.erase(e); @@ -299,8 +295,7 @@ class HighwayGraph { std::ofstream tmgfile(filename.data()); tmgfile << "TMG 1.0 simple\n"; tmgfile << vertices.size() << ' ' << simple_edge_count() << '\n'; - // number waypoint entries as we go to support original .gra - // format output + // number waypoint entries as we go int s_vertex_num = 0; for (std::pair wv : vertices) { char fstr[42]; @@ -316,16 +311,16 @@ class HighwayGraph // now edges, only print if not already printed int edge = 0; for (std::pair wv : vertices) - for (HighwayGraphEdgeInfo *e : wv.second->incident_s_edges) - if (!e->written) - { e->written = 1; + for (HGEdge *e : wv.second->incident_s_edges) + if (!e->s_written) + { e->s_written = 1; tmgfile << e->vertex1->s_vertex_num[0] << ' ' << e->vertex2->s_vertex_num[0] << ' ' << e->label(0) << '\n'; edge++; } // sanity checks for (std::pair wv : vertices) - for (HighwayGraphEdgeInfo *e : wv.second->incident_s_edges) - if (!e->written) + for (HGEdge *e : wv.second->incident_s_edges) + if (!e->s_written) std::cout << "ERROR: never wrote edge " << e->vertex1->s_vertex_num << ' ' << e->vertex2->s_vertex_num[0] << ' ' << e->label(0) << std::endl; if (simple_edge_count() != edge) std::cout << "ERROR: computed " << simple_edge_count() << " edges but wrote " << edge << std::endl; @@ -357,8 +352,8 @@ class HighwayGraph for (std::pair wv : vertices) if (!wv.second->is_hidden) for (HGEdge *e : wv.second->incident_c_edges) - if (!e->written) - { e->written = 1; + if (!e->c_written) + { e->c_written = 1; tmgfile << e->collapsed_tmg_line(0, threadnum) << '\n'; edge++; } @@ -383,7 +378,7 @@ class HighwayGraph std::ofstream simplefile(simplefilename.data()); std::ofstream collapfile(collapfilename.data()); std::unordered_set mv = matching_vertices(graph_vector[graphnum], cv_count); - std::unordered_set mse = matching_simple_edges(mv, graph_vector[graphnum]); + std::unordered_set mse = matching_simple_edges(mv, graph_vector[graphnum]); std::unordered_set mce = matching_collapsed_edges(mv, graph_vector[graphnum]); std::cout << graph_vector[graphnum].tag() << '(' << mv.size() << ',' << mse.size() << ") " @@ -411,7 +406,7 @@ class HighwayGraph } } // write edges - for (HighwayGraphEdgeInfo *e : mse) + for (HGEdge *e : mse) simplefile << e->vertex1->s_vertex_num[threadnum] << ' ' << e->vertex2->s_vertex_num[threadnum] << ' ' << e->label(graph_vector[graphnum].systems) << '\n'; diff --git a/siteupdate/cplusplus/classes/GraphGeneration/PlaceRadius.cpp b/siteupdate/cplusplus/classes/GraphGeneration/PlaceRadius.cpp index 390e52dc..71f6515e 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/PlaceRadius.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/PlaceRadius.cpp @@ -33,11 +33,6 @@ class PlaceRadius return ans <= r; } - bool contains_edge(HighwayGraphEdgeInfo *e) - { /* return whether both endpoints of edge e are within this area */ - return contains_vertex(e->vertex1) and contains_vertex(e->vertex2); - } - bool contains_edge(HGEdge *e) { /* return whether both endpoints of edge e are within this area */ return contains_vertex(e->vertex1) and contains_vertex(e->vertex2); diff --git a/siteupdate/cplusplus/classes/HighwaySystem.cpp b/siteupdate/cplusplus/classes/HighwaySystem.cpp index 8efba9ce..d0423c85 100644 --- a/siteupdate/cplusplus/classes/HighwaySystem.cpp +++ b/siteupdate/cplusplus/classes/HighwaySystem.cpp @@ -28,7 +28,7 @@ class HighwaySystem std::list con_route_list; std::unordered_map mileage_by_region; std::unordered_set vertices; - std::unordered_set edges; + std::unordered_set edges; HighwaySystem(std::string &line, ErrorList &el, std::string path, std::string &systemsfile, std::list> &countries, diff --git a/siteupdate/cplusplus/classes/Region.cpp b/siteupdate/cplusplus/classes/Region.cpp index c4919396..b879c3e5 100644 --- a/siteupdate/cplusplus/classes/Region.cpp +++ b/siteupdate/cplusplus/classes/Region.cpp @@ -41,7 +41,7 @@ class Region double overall_mileage; std::mutex *ao_mi_mtx, *ap_mi_mtx, *ov_mi_mtx; std::unordered_set vertices; - std::unordered_set edges; + std::unordered_set edges; Region (std::string &line, std::list> &countries, @@ -53,6 +53,7 @@ class Region ao_mi_mtx = new std::mutex; ap_mi_mtx = new std::mutex; ov_mi_mtx = new std::mutex; + // deleted on termination of program char *c_country = 0; char *c_continent = 0; // parse CSV line diff --git a/siteupdate/cplusplus/classes/Route/read_wpt.cpp b/siteupdate/cplusplus/classes/Route/read_wpt.cpp index aa863c37..e99c29fb 100644 --- a/siteupdate/cplusplus/classes/Route/read_wpt.cpp +++ b/siteupdate/cplusplus/classes/Route/read_wpt.cpp @@ -46,6 +46,7 @@ void Route::read_wpt } if (lines[l][0] == 0) continue; Waypoint *w = new Waypoint(lines[l], this, strtok_mtx, datacheckerrors); + // deleted on termination of program point_list.push_back(w); // populate unused alt labels for (size_t i = 0; i < w->alt_labels.size(); i++) @@ -64,6 +65,7 @@ void Route::read_wpt { // see if this is the first point colocated with other_w if (!other_w->colocated) { other_w->colocated = new std::list; + // deleted on termination of program other_w->colocated->push_front(other_w); } other_w->colocated->push_front(w); @@ -89,6 +91,7 @@ void Route::read_wpt { w->distance_update(datacheckerrors, fstr, vis_dist, point_list[point_list.size()-2]); // add HighwaySegment, if not first point segment_list.push_back(new HighwaySegment(point_list[point_list.size()-2], w, this)); + // deleted on termination of program } // checks for visible points if (!w->is_hidden) @@ -104,6 +107,7 @@ void Route::read_wpt w->label_looks_hidden(datacheckerrors); } } + delete[] wptdata; // per-route datachecks diff --git a/siteupdate/cplusplus/classes/WaypointQuadtree/WaypointQuadtree.cpp b/siteupdate/cplusplus/classes/WaypointQuadtree/WaypointQuadtree.cpp index 7305256e..3c1bdc8c 100644 --- a/siteupdate/cplusplus/classes/WaypointQuadtree/WaypointQuadtree.cpp +++ b/siteupdate/cplusplus/classes/WaypointQuadtree/WaypointQuadtree.cpp @@ -26,6 +26,7 @@ void WaypointQuadtree::refine() ne_child = new WaypointQuadtree(mid_lat, mid_lng, max_lat, max_lng); sw_child = new WaypointQuadtree(min_lat, min_lng, mid_lat, mid_lng); se_child = new WaypointQuadtree(min_lat, mid_lng, mid_lat, max_lng); + // deleted on termination of program for (Waypoint *p : points) insert(p); points.clear(); } diff --git a/siteupdate/cplusplus/functions/graph_generation.cpp b/siteupdate/cplusplus/functions/graph_generation.cpp index 10566c4b..ceec0d40 100644 --- a/siteupdate/cplusplus/functions/graph_generation.cpp +++ b/siteupdate/cplusplus/functions/graph_generation.cpp @@ -108,6 +108,7 @@ else { list *regions; for (Region ®ion : all_regions) { if (region.active_preview_mileage == 0) continue; regions = new list(1, ®ion); + // deleted on termination of program graph_vector.emplace_back(region.code + "-region", region.name + " (" + region.type + ")", 's', 'r', regions, (list*)0, (PlaceRadius*)0); graph_vector.emplace_back(region.code + "-region", region.name + " (" + region.type + ")", @@ -152,6 +153,7 @@ else { list *regions; } if (h) { systems = new list(1, h); + // deleted on termination of program graph_vector.emplace_back(h->systemname + "-system", h->systemname + " (" + h->fullname + ")", 's', 's', (list*)0, systems, (PlaceRadius*)0); graph_vector.emplace_back(h->systemname + "-system", h->systemname + " (" + h->fullname + ")", @@ -198,6 +200,7 @@ else { list *regions; continue; } systems = new list; + // deleted on termination of program list selected_systems; //FIXME rewrite this whole bit to be more compact for(char* token = strtok(fields[2], ","); token; token = strtok(0, ",")) selected_systems.push_back(token); @@ -253,6 +256,7 @@ else { list *regions; continue; } regions = new list; + // deleted on termination of program list selected_regions; //FIXME rewrite this whole bit to be more compact for(char* token = strtok(fields[2], ","); token; token = strtok(0, ",")) selected_regions.push_back(token); @@ -296,6 +300,7 @@ else { list *regions; // add entries to graph_vector for (pair &c : countries) { regions = new list; + // deleted on termination of program for (Region &r : all_regions) // does it match this country and have routes? if (&c == r.country && r.active_preview_mileage) @@ -336,6 +341,7 @@ else { list *regions; // add entries to graph_vector for (pair &c : continents) { regions = new list; + // deleted on termination of program for (Region &r : all_regions) // does it match this continent and have routes? if (&c == r.continent && r.active_preview_mileage) diff --git a/siteupdate/cplusplus/siteupdate.cpp b/siteupdate/cplusplus/siteupdate.cpp index 1959d1e8..6f72b801 100644 --- a/siteupdate/cplusplus/siteupdate.cpp +++ b/siteupdate/cplusplus/siteupdate.cpp @@ -24,7 +24,6 @@ class Region; class DatacheckEntryList; class HighwayGraph; class HGVertex; -class HighwayGraphEdgeInfo; class HGEdge; #include #include @@ -69,13 +68,11 @@ class HGEdge; #include "classes/ConnectedRoute.cpp" #include "classes/TravelerList/TravelerList.cpp" #include "classes/HighwaySegment/HighwaySegment.cpp" -#include "classes/GraphGeneration/HighwayGraphEdgeInfo.h" #include "classes/GraphGeneration/HGEdge.h" #include "classes/GraphGeneration/HGVertex.cpp" #include "classes/GraphGeneration/PlaceRadius.cpp" #include "classes/GraphGeneration/GraphListEntry.cpp" #include "classes/GraphGeneration/HighwayGraph.cpp" -#include "classes/GraphGeneration/HighwayGraphEdgeInfo.cpp" #include "classes/GraphGeneration/HGEdge.cpp" #include "threads/ReadWptThread.cpp" #include "threads/NmpMergedThread.cpp" @@ -202,6 +199,7 @@ int main(int argc, char *argv[]) continue; } HighwaySystem *hs = new HighwaySystem(line, el, args.highwaydatapath+"/hwy_data/_systems", args.systemsfile, countries, all_regions); + // deleted on termination of program if (hs->is_valid()) highway_systems.push_back(hs); else delete hs; cout << hs->systemname << '.' << std::flush; @@ -214,6 +212,7 @@ int main(int argc, char *argv[]) file.close(); DatacheckEntryList *datacheckerrors = new DatacheckEntryList; + // deleted on termination of program // check for duplicate .list names // and duplicate root entries among Route and ConnectedRoute @@ -596,6 +595,7 @@ int main(int argc, char *argv[]) if (other) if (!s->concurrent) { s->concurrent = new list; + // deleted on termination of program other->concurrent = s->concurrent; s->concurrent->push_back(s); s->concurrent->push_back(other); @@ -948,7 +948,6 @@ int main(int argc, char *argv[]) { el.add_error("Could not parse datacheckfps.csv line: [" + line + "], expected 6 fields, found more"); continue; } - char *rootstr = new char[line.size()-left]; fields[5] = line.substr(left+1); if (datacheck_always_error.find(fields[4]) != datacheck_always_error.end()) diff --git a/siteupdate/cplusplus/threads/ReadListThread.cpp b/siteupdate/cplusplus/threads/ReadListThread.cpp index b392bcd5..6f964fa9 100644 --- a/siteupdate/cplusplus/threads/ReadListThread.cpp +++ b/siteupdate/cplusplus/threads/ReadListThread.cpp @@ -14,5 +14,6 @@ void ReadListThread(std::list *traveler_ids, std::listunlock(); traveler_lists->push_back(new TravelerList(tl, route_hash, args, strtok_mtx)); + // deleted on termination of program } } From 641a0e8f9a715691cb57b2c95f5359cfafb6dd05 Mon Sep 17 00:00:00 2001 From: eric bryant Date: Tue, 2 Apr 2019 00:47:41 -0400 Subject: [PATCH 04/17] C++: concurrent travelers sanity check --- .../classes/HighwaySegment/HighwaySegment.cpp | 20 +++++++++++++++++++ .../classes/HighwaySegment/HighwaySegment.h | 1 + siteupdate/cplusplus/siteupdate.cpp | 8 ++++++++ 3 files changed, 29 insertions(+) diff --git a/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.cpp b/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.cpp index 2ec2c91c..4cb4427e 100644 --- a/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.cpp +++ b/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.cpp @@ -54,4 +54,24 @@ unsigned int HighwaySegment::index() return -1; // error; this segment not found in vector } +/*std::string HighwaySegment::concurrent_travelers_sanity_check() +{ if (route->system->devel()) return ""; + if (concurrent) + for (HighwaySegment *conc : *concurrent) + { if (clinched_by.size() != conc->clinched_by.size()) + { if (conc->route->system->devel()) continue; + return "[" + str() + "] clinched by " + std::to_string(clinched_by.size()) + " travelers; [" \ + + conc->str() + "] clinched by " + std::to_string(conc->clinched_by.size()) + '\n'; + } + else for (TravelerList *t : clinched_by) + { std::list::iterator ct; + for (ct = conc->clinched_by.begin(); ct != conc->clinched_by.end(); ct++) + if (*ct == t) break; + if (ct == conc->clinched_by.end()) + return t->traveler_name + " has clinched [" + str() + "], but not [" + conc->str() + "]\n"; + } + } + return ""; +}//*/ + #include "compute_stats.cpp" diff --git a/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.h b/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.h index a0d531b4..0bc94092 100644 --- a/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.h +++ b/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.h @@ -18,5 +18,6 @@ class HighwaySegment double length(); std::string segment_name(); unsigned int index(); + //std::string concurrent_travelers_sanity_check(); void compute_stats(); }; diff --git a/siteupdate/cplusplus/siteupdate.cpp b/siteupdate/cplusplus/siteupdate.cpp index 6f72b801..563e570a 100644 --- a/siteupdate/cplusplus/siteupdate.cpp +++ b/siteupdate/cplusplus/siteupdate.cpp @@ -648,6 +648,14 @@ int main(int argc, char *argv[]) cout << "!\n"; concurrencyfile.close(); + /*filename = args.logfilepath+"/concurrent_travelers_sanity_check.log"; + ofstream sanetravfile(filename.data()); + for (HighwaySystem *h : highway_systems) + for (Route &r : h->route_list) + for (HighwaySegment *s : r.segment_list) + sanetravfile << s->concurrent_travelers_sanity_check(); + sanetravfile.close(); //*/ + // compute lots of stats, first total mileage by route, system, overall, where // system and overall are stored in unordered_maps by region cout << et.et() << "Computing stats." << flush; From e6fc1fe14be8921ec6e9de25f91512e7b3dfd32d Mon Sep 17 00:00:00 2001 From: eric bryant Date: Tue, 2 Apr 2019 00:51:08 -0400 Subject: [PATCH 05/17] C++: delete unused source files --- .../GraphGeneration/HighwayGraphEdgeInfo.cpp | 75 ------------------- .../GraphGeneration/HighwayGraphEdgeInfo.h | 17 ----- 2 files changed, 92 deletions(-) delete mode 100644 siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphEdgeInfo.cpp delete mode 100644 siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphEdgeInfo.h diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphEdgeInfo.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphEdgeInfo.cpp deleted file mode 100644 index 5ae646de..00000000 --- a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphEdgeInfo.cpp +++ /dev/null @@ -1,75 +0,0 @@ -HighwayGraphEdgeInfo::HighwayGraphEdgeInfo(HighwaySegment *s, HighwayGraph *graph, bool &duplicate) -{ // temp debug [sic] - written = 0; - segment_name = s->segment_name(); - vertex1 = graph->vertices.at(s->waypoint1->hashpoint()); - vertex2 = graph->vertices.at(s->waypoint2->hashpoint()); - // checks for the very unusual cases where an edge ends up - // in the system as itself and its "reverse" - for (HighwayGraphEdgeInfo *e : vertex1->incident_s_edges) - if (e->vertex1 == vertex2 && e->vertex2 == vertex1) duplicate = 1; - for (HighwayGraphEdgeInfo *e : vertex2->incident_s_edges) - if (e->vertex1 == vertex2 && e->vertex2 == vertex1) duplicate = 1; - if (duplicate) - { delete this; - return; - } - vertex1->incident_s_edges.push_back(this); - vertex2->incident_s_edges.push_back(this); - // assumption: each edge/segment lives within a unique region - region = s->route->region; - region->edges.insert(this); - // a list of route name/system pairs - if (!s->concurrent) - { route_names_and_systems.emplace_back(s->route->list_entry_name(), s->route->system); - s->route->system->edges.insert(this); - } - else for (HighwaySegment *cs : *(s->concurrent)) - { if (cs->route->system->devel()) continue; - route_names_and_systems.emplace_back(cs->route->list_entry_name(), cs->route->system); - cs->route->system->edges.insert(this); - } -} - -HighwayGraphEdgeInfo::~HighwayGraphEdgeInfo() -{ for ( std::list::iterator e = vertex1->incident_s_edges.begin(); - e != vertex1->incident_s_edges.end(); - e++ - ) if (*e == this) - { vertex1->incident_s_edges.erase(e); - break; - } - for ( std::list::iterator e = vertex2->incident_s_edges.begin(); - e != vertex2->incident_s_edges.end(); - e++ - ) if (*e == this) - { vertex2->incident_s_edges.erase(e); - break; - } - segment_name.clear(); - route_names_and_systems.clear(); -} - -// compute an edge label, optionally resticted by systems -std::string HighwayGraphEdgeInfo::label(std::list *systems) -{ std::string the_label; - for (std::pair &ns : route_names_and_systems) - { // test whether system in systems - bool sys_in_sys = 0; - if (systems) for (HighwaySystem *h : *systems) - if (h == ns.second) - { sys_in_sys = 1; - break; - } - if (!systems || sys_in_sys) - if (the_label.empty()) - the_label = ns.first; - else the_label += "," + ns.first; - } - return the_label; -} - -// printable string for this edge -std::string HighwayGraphEdgeInfo::str() -{ return "HighwayGraphEdgeInfo: " + segment_name + " from " + *vertex1->unique_name + " to " + *vertex2->unique_name; -} diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphEdgeInfo.h b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphEdgeInfo.h deleted file mode 100644 index 0e339062..00000000 --- a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraphEdgeInfo.h +++ /dev/null @@ -1,17 +0,0 @@ -class HighwayGraphEdgeInfo -{ /* This class encapsulates information needed for a 'standard' - highway graph edge. - */ - public: - bool written; - std::string segment_name; - HGVertex *vertex1, *vertex2; - Region *region; - std::list> route_names_and_systems; - - HighwayGraphEdgeInfo(HighwaySegment *, HighwayGraph *, bool &); - ~HighwayGraphEdgeInfo(); - - std::string label(std::list *); - std::string str(); -}; From 6f77e3f4e80e8023fa10ea68ba000331090aaf9a Mon Sep 17 00:00:00 2001 From: eric bryant Date: Tue, 2 Apr 2019 01:57:19 -0400 Subject: [PATCH 06/17] C++: replace region with segment in HGEdge --- .../cplusplus/classes/GraphGeneration/HGEdge.cpp | 11 ++++++----- siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h | 2 +- .../classes/GraphGeneration/HighwayGraph.cpp | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp index 640eb9eb..f1c6cdbc 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp @@ -4,7 +4,7 @@ const unsigned char HGEdge::collapsed = 2; const unsigned char HGEdge::traveled = 4; HGEdge::HGEdge(HighwaySegment *s, HighwayGraph *graph) -{ // temp debug +{ // initial construction is based on a HighwaySegment s_written = 0; // simple c_written = 0; // collapsed vertex1 = graph->vertices.at(s->waypoint1->hashpoint()); @@ -27,11 +27,12 @@ HGEdge::HGEdge(HighwaySegment *s, HighwayGraph *graph) vertex2->incident_s_edges.push_back(this); vertex1->incident_c_edges.push_back(this); vertex2->incident_c_edges.push_back(this); + // canonical segment, used to reference region and list of travelers // assumption: each edge/segment lives within a unique region // and a 'multi-edge' would not be able to span regions as there // would be a required visible waypoint at the border - region = s->route->region; - region->edges.insert(this); + segment = s; + s->route->region->edges.insert(this); // a list of route name/system pairs if (!s->concurrent) { route_names_and_systems.emplace_back(s->route->list_entry_name(), s->route->system); @@ -64,10 +65,10 @@ HGEdge::HGEdge(HGVertex *vertex, unsigned char fmt_mask) segment_name = edge1->segment_name; //std::cout << "\nDEBUG: collapsing edges along " << segment_name << " at vertex " << \ *(vertex->unique_name) << ", edge1 is " << edge1->str() << " and edge2 is " << edge2->str() << std::endl; - // region and route names/systems should also match, but not + // segment and route names/systems should also match, but not // doing that sanity check here, as the above check should take // care of that - region = edge1->region; + segment = edge1->segment; route_names_and_systems = edge1->route_names_and_systems; // figure out and remember which endpoints are not the diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h index fc36b438..4cc6cc9f 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h +++ b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h @@ -7,7 +7,7 @@ class HGEdge std::string segment_name; HGVertex *vertex1, *vertex2; std::list intermediate_points; // if more than 1, will go from vertex1 to vertex2 - Region *region; + HighwaySegment *segment; std::list> route_names_and_systems; unsigned char format; diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp index 3d47a421..e6be7005 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp @@ -258,7 +258,7 @@ class HighwayGraph if (!g.placeradius || g.placeradius->contains_edge(e)) { bool rg_in_rg = 0; if (g.regions) for (Region *r : *g.regions) - if (r == e->region) + if (r == e->segment->route->region) { rg_in_rg = 1; break; } From bb04ab5152c67324efcfb6c4f2c539cc7c3c0895 Mon Sep 17 00:00:00 2001 From: eric bryant Date: Tue, 2 Apr 2019 03:12:04 -0400 Subject: [PATCH 07/17] C++: HGVertex: is_hidden -> visibility --- .../classes/GraphGeneration/HGVertex.cpp | 8 ++++---- .../classes/GraphGeneration/HighwayGraph.cpp | 20 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.cpp index 868eec71..292ccea7 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.cpp @@ -5,7 +5,7 @@ class HGVertex public: double lat, lng; const std::string *unique_name; - bool is_hidden; + char visibility; Waypoint *first_waypoint; std::unordered_set regions; std::unordered_set systems; @@ -22,12 +22,12 @@ class HGVertex // deleted by ~HGVertex, called by HighwayGraph::clear unique_name = n; // will consider hidden iff all colocated waypoints are hidden - is_hidden = 1; + visibility = 0; // note: if saving the first waypoint, no longer need // lat & lng and can replace with methods first_waypoint = wpt; if (!wpt->colocated) - { if (!wpt->is_hidden) is_hidden = 0; + { if (!wpt->is_hidden) visibility = 2; regions.insert(wpt->route->region); systems.insert(wpt->route->system); wpt->route->region->vertices.insert(this); @@ -35,7 +35,7 @@ class HGVertex return; } for (Waypoint *w : *(wpt->colocated)) - { if (!w->is_hidden) is_hidden = 0; + { if (!w->is_hidden) visibility = 2; regions.insert(w->route->region); systems.insert(w->route->system); w->route->region->vertices.insert(this); diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp index e6be7005..d429d3a7 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp @@ -98,10 +98,10 @@ class HighwayGraph for (std::pair wv : vertices) { if (counter % 10000 == 0) std::cout << '.' << std::flush; counter++; - if (wv.second->is_hidden) + if (!wv.second->visibility) { // cases with only one edge are flagged as HIDDEN_TERMINUS if (wv.second->incident_c_edges.size() < 2) - { wv.second->is_hidden = 0; + { wv.second->visibility = 2; continue; } // if >2 edges, flag HIDDEN_JUNCTION, mark as visible, and do not compress @@ -112,7 +112,7 @@ class HighwayGraph if (dcw->root_at_label() > (*it)->root_at_label()) dcw->root_at_label() = (*it)->root_at_label(); //TODO: WHAT THE...? How is this actually working? (Or is it?) datacheckerrors->add(dcw->route, dcw->label, "", "", "HIDDEN_JUNCTION", std::to_string(wv.second->incident_c_edges.size())); - wv.second->is_hidden = 0; + wv.second->visibility = 2; continue; } // construct from vertex this time @@ -131,7 +131,7 @@ class HighwayGraph unsigned int num_collapsed_vertices() { unsigned int count = 0; for (std::pair wv : vertices) - if (!wv.second->is_hidden) count ++; + if (wv.second->visibility == 2) count ++; return count; } @@ -145,7 +145,7 @@ class HighwayGraph unsigned int collapsed_edge_count() { unsigned int edges = 0; for (std::pair wv : vertices) - if (!wv.second->is_hidden) + if (wv.second->visibility == 2) edges += wv.second->incident_c_edges.size(); return edges/2; } @@ -200,7 +200,7 @@ class HighwayGraph } // find number of collapsed vertices for (HGVertex *v : vertex_set) - if (!v->is_hidden) cv_count++; + if (v->visibility == 2) cv_count++; return vertex_set; }//*/ @@ -253,7 +253,7 @@ class HighwayGraph // optionally restricted by region or system or placeradius std::unordered_set edge_set; for (HGVertex *v : mv) - { if (v->is_hidden) continue; + { if (v->visibility < 2) continue; for (HGEdge *e : v->incident_c_edges) if (!g.placeradius || g.placeradius->contains_edge(e)) { bool rg_in_rg = 0; @@ -340,7 +340,7 @@ class HighwayGraph // write visible vertices int c_vertex_num = 0; for (std::pair wv : vertices) - if (!wv.second->is_hidden) + if (wv.second->visibility == 2) { char fstr[42]; sprintf(fstr, "%.15g %.15g", wv.second->lat, wv.second->lng); tmgfile << *(wv.second->unique_name) << ' ' << fstr << '\n'; @@ -350,7 +350,7 @@ class HighwayGraph // write collapsed edges int edge = 0; for (std::pair wv : vertices) - if (!wv.second->is_hidden) + if (wv.second->visibility == 2) for (HGEdge *e : wv.second->incident_c_edges) if (!e->c_written) { e->c_written = 1; @@ -399,7 +399,7 @@ class HighwayGraph v->s_vertex_num[threadnum] = sv; sv++; // visible vertices, for collapsed graph - if (!v->is_hidden) + if (v->visibility == 2) { collapfile << *(v->unique_name) << fstr << '\n'; v->c_vertex_num[threadnum] = cv; cv++; From ff7e59144ca74ed0258f6dee190cd81a42a17db6 Mon Sep 17 00:00:00 2001 From: eric bryant Date: Tue, 2 Apr 2019 22:11:09 -0400 Subject: [PATCH 08/17] C++: tm-master-traveled.tmg partial implementation * Separate collection of "traveled" edges implemented. * fmt_mask allows new collapsed/traveled edges to be constructed together or separately as needed. * HighwayGraph.matching_vertices calculates & returns # of vertices for traveled graph, though this info is not used yet. * Traveled graph partially implemented: for now, just a glorified collapsed graph with a few extra vertices & edges. * Traveler numbers and hex codes are not yet implemented. * Subgraphs are not yet implemented. --- .../GraphGeneration/GraphListEntry.cpp | 2 + .../classes/GraphGeneration/HGEdge.cpp | 57 ++++++++- .../classes/GraphGeneration/HGEdge.h | 3 +- .../classes/GraphGeneration/HGVertex.cpp | 15 ++- .../classes/GraphGeneration/HighwayGraph.cpp | 112 +++++++++++++++--- .../classes/HighwaySegment/HighwaySegment.cpp | 8 +- .../classes/HighwaySegment/HighwaySegment.h | 4 +- .../cplusplus/functions/graph_generation.cpp | 13 +- 8 files changed, 176 insertions(+), 38 deletions(-) diff --git a/siteupdate/cplusplus/classes/GraphGeneration/GraphListEntry.cpp b/siteupdate/cplusplus/classes/GraphGeneration/GraphListEntry.cpp index 6265639e..23188593 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/GraphListEntry.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/GraphListEntry.cpp @@ -34,6 +34,7 @@ std::string GraphListEntry::filename() { switch (form) { case 's': return root+"-simple.tmg"; case 'c': return root+".tmg"; + case 't': return root+"-traveled.tmg"; default : return std::string("ERROR: GraphListEntry::filename() unexpected format token ('")+form+"')"; } } @@ -42,6 +43,7 @@ std::string GraphListEntry::format() { switch (form) { case 's': return "simple"; case 'c': return "collapsed"; + case 't': return "traveled"; default : return std::string("ERROR: GraphListEntry::format() unexpected format token ('")+form+"')"; } } diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp index f1c6cdbc..66645c8d 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp @@ -7,6 +7,7 @@ HGEdge::HGEdge(HighwaySegment *s, HighwayGraph *graph) { // initial construction is based on a HighwaySegment s_written = 0; // simple c_written = 0; // collapsed + t_written = 0; // traveled vertex1 = graph->vertices.at(s->waypoint1->hashpoint()); vertex2 = graph->vertices.at(s->waypoint2->hashpoint()); // checks for the very unusual cases where an edge ends up @@ -27,6 +28,8 @@ HGEdge::HGEdge(HighwaySegment *s, HighwayGraph *graph) vertex2->incident_s_edges.push_back(this); vertex1->incident_c_edges.push_back(this); vertex2->incident_c_edges.push_back(this); + vertex1->incident_t_edges.push_back(this); + vertex2->incident_t_edges.push_back(this); // canonical segment, used to reference region and list of travelers // assumption: each edge/segment lives within a unique region // and a 'multi-edge' would not be able to span regions as there @@ -50,12 +53,23 @@ HGEdge::HGEdge(HGVertex *vertex, unsigned char fmt_mask) // hidden vertex waypoint, whose information is given in // vertex c_written = 0; + t_written = 0; format = fmt_mask; // we know there are exactly 2 incident edges, as we // checked for that, and we will replace these two - // with the single edge we are constructing here - HGEdge *edge1 = vertex->incident_c_edges.front(); - HGEdge *edge2 = vertex->incident_c_edges.back(); + // with the single edge we are constructing here... + HGEdge *edge1 = 0; + HGEdge *edge2 = 0; + if (fmt_mask & collapsed) + { // ...in the compressed graph, and/or... + edge1 = vertex->incident_c_edges.front(); + edge2 = vertex->incident_c_edges.back(); + } + if (fmt_mask & traveled) + { // ...in the traveled graph, as appropriate + edge1 = vertex->incident_t_edges.front(); + edge2 = vertex->incident_t_edges.back(); + } // segment names should match as routes should not start or end // nor should concurrencies begin or end at a hidden point if (edge1->segment_name != edge2->segment_name) @@ -108,8 +122,14 @@ HGEdge::HGEdge(HGVertex *vertex, unsigned char fmt_mask) edge2->detach(fmt_mask); if (!edge1->format) delete edge1; if (!edge2->format) delete edge2; - vertex1->incident_c_edges.push_back(this); - vertex2->incident_c_edges.push_back(this); + if (fmt_mask & collapsed) + { vertex1->incident_c_edges.push_back(this); + vertex2->incident_c_edges.push_back(this); + } + if (fmt_mask & traveled) + { vertex1->incident_t_edges.push_back(this); + vertex2->incident_t_edges.push_back(this); + } } void HGEdge::detach(unsigned char fmt_mask) @@ -145,6 +165,22 @@ void HGEdge::detach(unsigned char fmt_mask) break; } } + if (fmt_mask & traveled) + { for ( std::list::iterator e = vertex1->incident_t_edges.begin(); + e != vertex1->incident_t_edges.end(); + e++ + ) if (*e == this) + { vertex1->incident_t_edges.erase(e); + break; + } + for ( std::list::iterator e = vertex2->incident_t_edges.begin(); + e != vertex2->incident_t_edges.end(); + e++ + ) if (*e == this) + { vertex2->incident_t_edges.erase(e); + break; + } + } format &= ~fmt_mask; } @@ -191,6 +227,17 @@ std::string HGEdge::collapsed_tmg_line(std::list *systems, unsig return line; } +// line appropriate for a tmg traveled edge file +std::string HGEdge::traveled_tmg_line(std::list *systems, unsigned int threadnum) +{ std::string line = std::to_string(vertex1->t_vertex_num[threadnum]) + " " + std::to_string(vertex2->t_vertex_num[threadnum]) + " " + label(systems); + char fstr[43]; + for (HGVertex *intermediate : intermediate_points) + { sprintf(fstr, " %.15g %.15g", intermediate->lat, intermediate->lng); + line += fstr; + } + return line; +} + // line appropriate for a tmg collapsed edge file, with debug info std::string HGEdge::debug_tmg_line(std::list *systems, unsigned int threadnum) { std::string line = std::to_string(vertex1->c_vertex_num[threadnum]) + " [" + *vertex1->unique_name + "] " \ diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h index 4cc6cc9f..3b374224 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h +++ b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h @@ -3,7 +3,7 @@ class HGEdge edge that can incorporate intermediate points. */ public: - bool s_written, c_written; // simple, collapsed + bool s_written, c_written, t_written; // simple, collapsed, traveled std::string segment_name; HGVertex *vertex1, *vertex2; std::list intermediate_points; // if more than 1, will go from vertex1 to vertex2 @@ -23,6 +23,7 @@ class HGEdge void detach(unsigned char); std::string label(std::list *); std::string collapsed_tmg_line(std::list *, unsigned int); + std::string traveled_tmg_line(std::list *, unsigned int); std::string debug_tmg_line(std::list *, unsigned int); std::string str(); std::string intermediate_point_string(); diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.cpp index 292ccea7..ae9c1364 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HGVertex.cpp @@ -9,20 +9,26 @@ class HGVertex Waypoint *first_waypoint; std::unordered_set regions; std::unordered_set systems; - std::list incident_s_edges; - std::list incident_c_edges; + std::list incident_s_edges; // simple + std::list incident_c_edges; // collapsed + std::list incident_t_edges; // traveled int *s_vertex_num; int *c_vertex_num; + int *t_vertex_num; HGVertex(Waypoint *wpt, const std::string *n, DatacheckEntryList *datacheckerrors, unsigned int numthreads) { lat = wpt->lat; lng = wpt->lng; s_vertex_num = new int[numthreads]; c_vertex_num = new int[numthreads]; + t_vertex_num = new int[numthreads]; // deleted by ~HGVertex, called by HighwayGraph::clear unique_name = n; - // will consider hidden iff all colocated waypoints are hidden visibility = 0; + // permitted values: + // 0: never visible outside of simple graphs + // 1: visible only in traveled graph; hidden in collapsed graph + // 2: visible in both traveled & collapsed graphs // note: if saving the first waypoint, no longer need // lat & lng and can replace with methods first_waypoint = wpt; @@ -35,7 +41,8 @@ class HGVertex return; } for (Waypoint *w : *(wpt->colocated)) - { if (!w->is_hidden) visibility = 2; + { // will consider hidden iff all colocated waypoints are hidden + if (!w->is_hidden) visibility = 2; regions.insert(w->route->region); systems.insert(w->route->system); w->route->region->vertices.insert(this); diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp index d429d3a7..0956b232 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp @@ -4,9 +4,10 @@ class HighwayGraph On construction, build a set of unique vertex names and determine edges, at most one per concurrent segment. - Create two sets of edges - one for the full graph - and one for the graph with hidden waypoints compressed into - multi-point edges. + Create three sets of edges: + - one for the simple graph + - one for the collapsed graph with hidden waypoints compressed into multi-point edges + - one for the traveled graph: collapsed edges split at endpoints of users' travels */ public: @@ -90,7 +91,7 @@ class HighwayGraph new HGEdge(s, this); // deleted by ~HGVertex, called by HighwayGraph::clear } - std::cout << "!\n" << et.et() << "Full graph has " << vertices.size() << " vertices, " << simple_edge_count() << " edges." << std::endl; + std::cout << '!' << std::endl; // compress edges adjacent to hidden vertices counter = 0; @@ -115,17 +116,41 @@ class HighwayGraph wv.second->visibility = 2; continue; } + // if edge clinched_by sets mismatch, set visibility to 1 + // (visible in traveled graph; hidden in collapsed graph) + // first, the easy check, for whether set sizes mismatch + if (wv.second->incident_t_edges.front()->segment->clinched_by.size() + != wv.second->incident_t_edges.back()->segment->clinched_by.size()) + wv.second->visibility = 1; + // next, compare clinched_by sets; look for any element in the 1st not in the 2nd + else for (TravelerList *t : wv.second->incident_t_edges.front()->segment->clinched_by) + if (wv.second->incident_t_edges.back()->segment->clinched_by.find(t) + == wv.second->incident_t_edges.back()->segment->clinched_by.end()) + { wv.second->visibility = 1; + break; + } // construct from vertex this time - new HGEdge(wv.second, HGEdge::collapsed); - // Final collapsed edges are deleted by ~HGVertex, called by HighwayGraph::clear. - // Partially collapsed edges created during the compression process are deleted - // upon detachment from all graphs. + if (wv.second->visibility == 1) + new HGEdge(wv.second, HGEdge::collapsed); + else if ((wv.second->incident_c_edges.front() == wv.second->incident_t_edges.front() + && wv.second->incident_c_edges.back() == wv.second->incident_t_edges.back()) + || (wv.second->incident_c_edges.front() == wv.second->incident_t_edges.back() + && wv.second->incident_c_edges.back() == wv.second->incident_t_edges.front())) + new HGEdge(wv.second, HGEdge::collapsed | HGEdge::traveled); + else { new HGEdge(wv.second, HGEdge::collapsed); + new HGEdge(wv.second, HGEdge::traveled); + // Final collapsed edges are deleted by ~HGVertex, called by HighwayGraph::clear. + // Partially collapsed edges created during the compression process are deleted + // upon detachment from all graphs. + } } } + std::cout << '!' << std::endl; // print summary info - std::cout << "!\n" << et.et() << "Edge compressed graph has " << num_collapsed_vertices() - << " vertices, " << collapsed_edge_count() << " edges." << std::endl; + std::cout << et.et() << " Simple graph has " << vertices.size() << " vertices, " << simple_edge_count() << " edges." << std::endl; + std::cout << et.et() << "Collapsed graph has " << num_collapsed_vertices() << " vertices, " << collapsed_edge_count() << " edges." << std::endl; + std::cout << et.et() << " Traveled graph has " << num_traveled_vertices() << " vertices, " << traveled_edge_count() << " edges." << std::endl; } // end ctor unsigned int num_collapsed_vertices() @@ -135,6 +160,13 @@ class HighwayGraph return count; } + unsigned int num_traveled_vertices() + { unsigned int count = 0; + for (std::pair wv : vertices) + if (wv.second->visibility >= 1) count ++; + return count; + } + unsigned int simple_edge_count() { unsigned int edges = 0; for (std::pair wv : vertices) @@ -150,6 +182,14 @@ class HighwayGraph return edges/2; } + unsigned int traveled_edge_count() + { unsigned int edges = 0; + for (std::pair wv : vertices) + if (wv.second->visibility >= 1) + edges += wv.second->incident_t_edges.size(); + return edges/2; + } + void clear() { for (std::pair wv : vertices) delete wv.second; vertex_names.clear(); @@ -157,10 +197,13 @@ class HighwayGraph vertices.clear(); } - std::unordered_set matching_vertices(GraphListEntry &g, unsigned int &cv_count) + std::unordered_set matching_vertices(GraphListEntry &g, unsigned int &cv_count, unsigned int &tv_count) { // Return a set of vertices from the graph, optionally // restricted by region or system or placeradius area. + // Keep a count of collapsed & traveled vertices as we + // go, and pass them by reference. cv_count = 0; + tv_count = 0; std::unordered_set vertex_set; std::unordered_set rg_vertex_set; std::unordered_set sys_vertex_set; @@ -198,9 +241,12 @@ class HighwayGraph v = vertex_set.erase(v); else v++; } - // find number of collapsed vertices + // find number of collapsed/traveled vertices for (HGVertex *v : vertex_set) - if (v->visibility == 2) cv_count++; + if (v->visibility >= 1) + { tv_count++; + if (v->visibility == 2) cv_count++; + } return vertex_set; }//*/ @@ -366,18 +412,54 @@ class HighwayGraph mcptr->edges = num_collapsed_edges; } + // write the entire set of data in the tmg traveled format + void write_master_tmg_traveled(GraphListEntry *mtptr, std::string filename, unsigned int threadnum) + { std::ofstream tmgfile(filename.data()); + unsigned int num_traveled_edges = traveled_edge_count(); + tmgfile << "TMG 2.0 traveled\n"; + tmgfile << num_traveled_vertices() << " " << num_traveled_edges << '\n'; + + // write visible vertices + int t_vertex_num = 0; + for (std::pair wv : vertices) + if (wv.second->visibility >= 1) + { char fstr[42]; + sprintf(fstr, "%.15g %.15g", wv.second->lat, wv.second->lng); + tmgfile << *(wv.second->unique_name) << ' ' << fstr << '\n'; + wv.second->t_vertex_num[threadnum] = t_vertex_num; + t_vertex_num++; + } + // write traveled edges + int edge = 0; + for (std::pair wv : vertices) + if (wv.second->visibility >= 1) + for (HGEdge *e : wv.second->incident_t_edges) + if (!e->t_written) + { e->t_written = 1; + tmgfile << e->traveled_tmg_line(0, threadnum) << '\n'; + edge++; + } + // sanity check on edges written + if (num_traveled_edges != edge) + std::cout << "ERROR: computed " << num_traveled_edges << " traveled edges, but wrote " << edge << '\n'; + + tmgfile.close(); + mtptr->vertices = num_traveled_vertices(); + mtptr->edges = num_traveled_edges; + } + // write a subset of the data, // in both simple and collapsed formats, // restricted by regions in the list if given, // by systems in the list if given, // or to within a given area if placeradius is given void write_subgraphs_tmg(std::vector &graph_vector, std::string path, size_t graphnum, unsigned int threadnum) - { unsigned int cv_count; + { unsigned int cv_count, tv_count; std::string simplefilename = path+graph_vector[graphnum].filename(); std::string collapfilename = path+graph_vector[graphnum+1].filename(); std::ofstream simplefile(simplefilename.data()); std::ofstream collapfile(collapfilename.data()); - std::unordered_set mv = matching_vertices(graph_vector[graphnum], cv_count); + std::unordered_set mv = matching_vertices(graph_vector[graphnum], cv_count, tv_count); std::unordered_set mse = matching_simple_edges(mv, graph_vector[graphnum]); std::unordered_set mce = matching_collapsed_edges(mv, graph_vector[graphnum]); std::cout << graph_vector[graphnum].tag() diff --git a/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.cpp b/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.cpp index 4cb4427e..1756b154 100644 --- a/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.cpp +++ b/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.cpp @@ -11,13 +11,9 @@ std::string HighwaySegment::str() bool HighwaySegment::add_clinched_by(TravelerList *traveler) { clin_mtx.lock(); - for (TravelerList *t : clinched_by) if (t == traveler) - { clin_mtx.unlock(); - return 0; - } - clinched_by.push_front(traveler); + bool result = clinched_by.insert(traveler).second; clin_mtx.unlock(); - return 1; + return result; } std::string HighwaySegment::csv_line(unsigned int id) diff --git a/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.h b/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.h index 0bc94092..b1e16712 100644 --- a/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.h +++ b/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.h @@ -7,13 +7,13 @@ class HighwaySegment Waypoint *waypoint2; Route *route; std::list *concurrent; - std::forward_list clinched_by; //FIXME try unordered_set? + std::unordered_set clinched_by; std::mutex clin_mtx; HighwaySegment(Waypoint *, Waypoint *, Route *); std::string str(); - bool add_clinched_by(TravelerList *); //FIXME rework to use unordered_set? Simpler coding, probably faster + bool add_clinched_by(TravelerList *); std::string csv_line(unsigned int); double length(); std::string segment_name(); diff --git a/siteupdate/cplusplus/functions/graph_generation.cpp b/siteupdate/cplusplus/functions/graph_generation.cpp index ceec0d40..c54d6242 100644 --- a/siteupdate/cplusplus/functions/graph_generation.cpp +++ b/siteupdate/cplusplus/functions/graph_generation.cpp @@ -24,16 +24,19 @@ else { list *regions; graph_vector.emplace_back("tm-master", "All Travel Mapping Data", 's', 'M', (list*)0, (list*)0, (PlaceRadius*)0); graph_vector.emplace_back("tm-master", "All Travel Mapping Data", 'c', 'M', (list*)0, (list*)0, (PlaceRadius*)0); + graph_vector.emplace_back("tm-master", "All Travel Mapping Data", 't', 'M', (list*)0, (list*)0, (PlaceRadius*)0); - #ifdef threading_enabled + /*#ifdef threading_enabled if (args.numthreads <= 1) - #endif + #endif//*/ { cout << et.et() << "Writing master TM simple graph file, tm-master-simple.tmg" << endl; graph_data.write_master_tmg_simple(&graph_vector[0], args.graphfilepath+"/tm-master-simple.tmg"); cout << et.et() << "Writing master TM collapsed graph file, tm-master.tmg." << endl; graph_data.write_master_tmg_collapsed(&graph_vector[1], args.graphfilepath+"/tm-master.tmg", 0); + cout << et.et() << "Writing master TM traveled graph file, tm-master.tmg." << endl; + graph_data.write_master_tmg_traveled(&graph_vector[2], args.graphfilepath+"/tm-master-traveled.tmg", 0); } - #ifdef threading_enabled + /*#ifdef threading_enabled else { cout << et.et() << "Writing master TM simple graph file, tm-master-simple.tmg" << endl; thr[0] = new thread(MasterTmgSimpleThread, &graph_data, &graph_vector[0], args.graphfilepath+"/tm-master-simple.tmg"); cout << et.et() << "Writing master TM collapsed graph file, tm-master.tmg." << endl; @@ -43,10 +46,10 @@ else { list *regions; delete thr[0]; delete thr[1]; } - #endif + #endif//*/ graph_types.push_back({"master", "All Travel Mapping Data", "These graphs contain all routes currently plotted in the Travel Mapping project."}); - size_t graphnum = 2; + size_t graphnum = 3; // graphs restricted by place/area - from areagraphs.csv file From 8c7af6289bb41959e5c80c1efe06db80bc323d97 Mon Sep 17 00:00:00 2001 From: eric bryant Date: Wed, 3 Apr 2019 15:24:26 -0400 Subject: [PATCH 09/17] C++: traveled edge compression bugfix Due to using std::list::splice, when compressing a vertex into both traveled & "normal" collapsed edges separately, the intermediate points were removed from edge2's list during collapsed edge construction, and thus no longer available to be spliced into the new traveled edge's list. This resulted in traveled edges with missing intermediate points. --- .../classes/GraphGeneration/HGEdge.cpp | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp index 66645c8d..95c17aed 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp @@ -22,7 +22,7 @@ HGEdge::HGEdge(HighwaySegment *s, HighwayGraph *graph) { delete this; return; } - format = simple | collapsed; + format = simple | collapsed | traveled; segment_name = s->segment_name(); vertex1->incident_s_edges.push_back(this); vertex2->incident_s_edges.push_back(this); @@ -77,8 +77,12 @@ HGEdge::HGEdge(HGVertex *vertex, unsigned char fmt_mask) std::cout << "edge1 named " << edge1->segment_name << " edge2 named " << edge2->segment_name << '\n' << std::endl; } segment_name = edge1->segment_name; - //std::cout << "\nDEBUG: collapsing edges along " << segment_name << " at vertex " << \ - *(vertex->unique_name) << ", edge1 is " << edge1->str() << " and edge2 is " << edge2->str() << std::endl; + /*std::cout << "\nDEBUG: collapsing edges |"; + if (fmt_mask & collapsed) std::cout << 'c'; else std::cout << '-'; + if (fmt_mask & traveled) std::cout << 't'; else std::cout << '-'; + std::cout << "| along " << segment_name << " at vertex " << *(vertex->unique_name); + std::cout << "\n edge1 is " << edge1->str(); + std::cout << "\n edge2 is " << edge2->str() << std::endl;//*/ // segment and route names/systems should also match, but not // doing that sanity check here, as the above check should take // care of that @@ -107,15 +111,16 @@ HGEdge::HGEdge(HGVertex *vertex, unsigned char fmt_mask) if (edge2->vertex1 == vertex) { //std::cout << "DEBUG: vertex2 getting edge2->vertex2: " << *(edge2->vertex2->unique_name) << std::endl; vertex2 = edge2->vertex2; + intermediate_points.insert(intermediate_points.end(), edge2->intermediate_points.begin(), edge2->intermediate_points.end()); } - else { //std:: cout << "DEBUG: vertex2 getting edge2->vertex1: " << *(edge2->vertex1->unique_name) << " and reversing edge2 intermediates" << std::endl; + else { //std::cout << "DEBUG: vertex2 getting edge2->vertex1: " << *(edge2->vertex1->unique_name) << " and reversing edge2 intermediates" << std::endl; vertex2 = edge2->vertex1; - edge2->intermediate_points.reverse(); + intermediate_points.insert(intermediate_points.end(), edge2->intermediate_points.rbegin(), edge2->intermediate_points.rend()); } - intermediate_points.splice(intermediate_points.end(), edge2->intermediate_points); //std::cout << "DEBUG: intermediates complete: from " << *(vertex1->unique_name) << " via " << \ intermediate_point_string() << " to " << *(vertex2->unique_name) << std::endl; + //std::cout << "DEBUG: new " << str() << std::endl; // replace edge references at our endpoints with ourself edge1->detach(fmt_mask); @@ -252,10 +257,16 @@ std::string HGEdge::debug_tmg_line(std::list *systems, unsigned // printable string for this edge std::string HGEdge::str() -{ return "HGEdge: " + segment_name +{ std::string str = "HGEdge |"; + if (format & simple) str += 's'; else str += '-'; + if (format & collapsed) str += 'c'; else str += '-'; + if (format & traveled) str += 't'; else str += '-'; + str += "|: " + segment_name + " from " + *vertex1->unique_name + " to " + *vertex2->unique_name - + " via " + std::to_string(intermediate_points.size()) + " points"; + + " via " + std::to_string(intermediate_points.size()) + " points {" + + std::to_string((long long unsigned int)this) + '}'; + return str; } // return the intermediate points as a string From 668fb97b974bad49a634179213b9d8f5e39cbb38 Mon Sep 17 00:00:00 2001 From: eric bryant Date: Sat, 6 Apr 2019 13:05:09 -0400 Subject: [PATCH 10/17] C++: hex codes for traveled graphs plus a bugfix: added a mutex around writing to traveler_lists when reading .list files from disk --- .../classes/GraphGeneration/HGEdge.cpp | 3 +- .../classes/GraphGeneration/HGEdge.h | 2 +- .../classes/GraphGeneration/HighwayGraph.cpp | 13 +++++--- .../classes/HighwaySegment/HighwaySegment.cpp | 24 +++++++++++++++ .../classes/HighwaySegment/HighwaySegment.h | 1 + siteupdate/cplusplus/classes/Route/Route.h | 4 +-- .../classes/TravelerList/TravelerList.cpp | 4 +++ .../cplusplus/functions/graph_generation.cpp | 30 +++++++++---------- siteupdate/cplusplus/siteupdate.cpp | 6 ++++ .../cplusplus/threads/ReadListThread.cpp | 7 +++-- .../cplusplus/threads/SubgraphThread.cpp | 5 ++-- 11 files changed, 72 insertions(+), 27 deletions(-) diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp index 95c17aed..04bb7209 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.cpp @@ -233,8 +233,9 @@ std::string HGEdge::collapsed_tmg_line(std::list *systems, unsig } // line appropriate for a tmg traveled edge file -std::string HGEdge::traveled_tmg_line(std::list *systems, unsigned int threadnum) +std::string HGEdge::traveled_tmg_line(std::list *systems, std::list *traveler_lists, unsigned int threadnum) { std::string line = std::to_string(vertex1->t_vertex_num[threadnum]) + " " + std::to_string(vertex2->t_vertex_num[threadnum]) + " " + label(systems); + line += " " + segment->clinchedby_code(traveler_lists); char fstr[43]; for (HGVertex *intermediate : intermediate_points) { sprintf(fstr, " %.15g %.15g", intermediate->lat, intermediate->lng); diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h index 3b374224..7b6374e0 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h +++ b/siteupdate/cplusplus/classes/GraphGeneration/HGEdge.h @@ -23,7 +23,7 @@ class HGEdge void detach(unsigned char); std::string label(std::list *); std::string collapsed_tmg_line(std::list *, unsigned int); - std::string traveled_tmg_line(std::list *, unsigned int); + std::string traveled_tmg_line(std::list *, std::list *, unsigned int); std::string debug_tmg_line(std::list *, unsigned int); std::string str(); std::string intermediate_point_string(); diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp index 0956b232..af15855d 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp @@ -413,7 +413,7 @@ class HighwayGraph } // write the entire set of data in the tmg traveled format - void write_master_tmg_traveled(GraphListEntry *mtptr, std::string filename, unsigned int threadnum) + void write_master_tmg_traveled(GraphListEntry *mtptr, std::string filename, std::list *traveler_lists, unsigned int threadnum) { std::ofstream tmgfile(filename.data()); unsigned int num_traveled_edges = traveled_edge_count(); tmgfile << "TMG 2.0 traveled\n"; @@ -436,9 +436,13 @@ class HighwayGraph for (HGEdge *e : wv.second->incident_t_edges) if (!e->t_written) { e->t_written = 1; - tmgfile << e->traveled_tmg_line(0, threadnum) << '\n'; + tmgfile << e->traveled_tmg_line(0, traveler_lists, threadnum) << '\n'; edge++; } + // traveler names + for (TravelerList *t : *traveler_lists) + tmgfile << t->traveler_name << ' '; + // sanity check on edges written if (num_traveled_edges != edge) std::cout << "ERROR: computed " << num_traveled_edges << " traveled edges, but wrote " << edge << '\n'; @@ -449,11 +453,12 @@ class HighwayGraph } // write a subset of the data, - // in both simple and collapsed formats, + // in simple, collapsed and traveled formats, // restricted by regions in the list if given, // by systems in the list if given, // or to within a given area if placeradius is given - void write_subgraphs_tmg(std::vector &graph_vector, std::string path, size_t graphnum, unsigned int threadnum) + void write_subgraphs_tmg(std::vector &graph_vector, std::string path, size_t graphnum, + unsigned int threadnum, std::list *traveler_lists) { unsigned int cv_count, tv_count; std::string simplefilename = path+graph_vector[graphnum].filename(); std::string collapfilename = path+graph_vector[graphnum+1].filename(); diff --git a/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.cpp b/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.cpp index 1756b154..2020cc52 100644 --- a/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.cpp +++ b/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.cpp @@ -70,4 +70,28 @@ unsigned int HighwaySegment::index() return ""; }//*/ +std::string HighwaySegment::clinchedby_code(std::list *traveler_lists) +{ // Return a hexadecimal string encoding which travelers have clinched this segment, for use in "traveled" graph files + // Each character stores info for traveler #n thru traveler #n+3 + // The first character stores traveler 0 thru traveler 3, + // The second character stores traveler 4 thru traveler 7, etc. + // For each character, the low-order bit stores traveler n, and the high bit traveler n+3. + std::string code(ceil(double(traveler_lists->size())/4), '0'); + //std::cout << str() << " code string initialized (" << clinched_by.size() << '/' << traveler_lists->size() << ')' << std::endl; + //unsigned int num = 0; + for (TravelerList* t : clinched_by) + { //std::cout << "\t" << num << ": TravNum = " << t->traveler_num << ": " << t->traveler_name << std::endl; + //std::cout << "\t" << num << ": TravNum/4 = " << t->traveler_num/4 << std::endl; + //std::cout << "\t" << num << ": TravNum%4 = " << TravNum%4 << std::endl; + //std::cout << "\t" << num << ": 2 ^ TravNum%4 = " << pow(2, TravNum%4) << std::endl; + //std::cout << "\t" << num << ": code[" << TravNum/4 << "] += int(" << pow(2, TravNum%4) << ")" << std::endl; + code[t->traveler_num/4] += int(pow(2, t->traveler_num%4)); + //num++; + } + //std::cout << "travelers written to array" << std::endl; + for (char &nibble : code) if (nibble > '9') nibble += 7; + //std::cout << "nibbles >9 -> letters" << std::endl; + return code; +} + #include "compute_stats.cpp" diff --git a/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.h b/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.h index b1e16712..6b3c0176 100644 --- a/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.h +++ b/siteupdate/cplusplus/classes/HighwaySegment/HighwaySegment.h @@ -19,5 +19,6 @@ class HighwaySegment std::string segment_name(); unsigned int index(); //std::string concurrent_travelers_sanity_check(); + std::string clinchedby_code(std::list *); void compute_stats(); }; diff --git a/siteupdate/cplusplus/classes/Route/Route.h b/siteupdate/cplusplus/classes/Route/Route.h index 9d749ad0..102ac87b 100644 --- a/siteupdate/cplusplus/classes/Route/Route.h +++ b/siteupdate/cplusplus/classes/Route/Route.h @@ -49,10 +49,10 @@ class Route std::vector point_list; std::unordered_set labels_in_use; std::unordered_set unused_alt_labels; + static std::mutex awf_mtx; // for locking the all_wpt_files set when erasing processed WPTs static std::mutex liu_mtx; // for locking the labels_in_use set when inserting labels during TravelerList processing static std::mutex ual_mtx; // for locking the unused_alt_labels set when removing in-use alt_labels - // with one for each route, rather than static, no discernable speed difference. Saving a wee bit of RAM. - static std::mutex awf_mtx; // for locking the all_wpt_files set when erasing processed WPTs + // with one for each route, rather than static, no discernable speed difference. Saving a wee bit of RAM. std::vector segment_list; double mileage; int rootOrder; diff --git a/siteupdate/cplusplus/classes/TravelerList/TravelerList.cpp b/siteupdate/cplusplus/classes/TravelerList/TravelerList.cpp index 35278797..00189431 100644 --- a/siteupdate/cplusplus/classes/TravelerList/TravelerList.cpp +++ b/siteupdate/cplusplus/classes/TravelerList/TravelerList.cpp @@ -23,10 +23,12 @@ class TravelerList std::unordered_map routes_traveled; // mileage per traveled route std::unordered_map con_routes_clinched; // clinch count per system //std::unordered_map routes_clinched; // commented out in original siteupdate.py + unsigned int traveler_num; unsigned int active_systems_traveled; unsigned int active_systems_clinched; unsigned int preview_systems_traveled; unsigned int preview_systems_clinched; + static std::mutex alltrav_mtx; // for locking the traveler_lists list when reading .lists from disk TravelerList(std::string travname, std::unordered_map *route_hash, Arguments *args, std::mutex *strtok_mtx) { active_systems_traveled = 0; @@ -195,6 +197,8 @@ class TravelerList #include "userlog.cpp" }; +std::mutex TravelerList::alltrav_mtx; + bool sort_travelers_by_name(const TravelerList *t1, const TravelerList *t2) { return t1->traveler_name < t2->traveler_name; } diff --git a/siteupdate/cplusplus/functions/graph_generation.cpp b/siteupdate/cplusplus/functions/graph_generation.cpp index c54d6242..ed70e02e 100644 --- a/siteupdate/cplusplus/functions/graph_generation.cpp +++ b/siteupdate/cplusplus/functions/graph_generation.cpp @@ -34,7 +34,7 @@ else { list *regions; cout << et.et() << "Writing master TM collapsed graph file, tm-master.tmg." << endl; graph_data.write_master_tmg_collapsed(&graph_vector[1], args.graphfilepath+"/tm-master.tmg", 0); cout << et.et() << "Writing master TM traveled graph file, tm-master.tmg." << endl; - graph_data.write_master_tmg_traveled(&graph_vector[2], args.graphfilepath+"/tm-master-traveled.tmg", 0); + graph_data.write_master_tmg_traveled(&graph_vector[2], args.graphfilepath+"/tm-master-traveled.tmg", &traveler_lists, 0); } /*#ifdef threading_enabled else { cout << et.et() << "Writing master TM simple graph file, tm-master-simple.tmg" << endl; @@ -84,14 +84,14 @@ else { list *regions; #ifdef threading_enabled // set up for threaded subgraph generation for (unsigned int t = 0; t < args.numthreads; t++) - thr[t] = new thread(SubgraphThread, t, &graph_data, &graph_vector, &graphnum, &list_mtx, args.graphfilepath + "/"); + thr[t] = new thread(SubgraphThread, t, &graph_data, &graph_vector, &graphnum, &list_mtx, args.graphfilepath + "/", &traveler_lists); for (unsigned int t = 0; t < args.numthreads; t++) thr[t]->join(); for (unsigned int t = 0; t < args.numthreads; t++) delete thr[t]; #else while (graphnum < graph_vector.size()) - { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0); + { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0, &traveler_lists); graphnum += 2; } #endif @@ -121,14 +121,14 @@ else { list *regions; #ifdef threading_enabled // set up for threaded subgraph generation for (unsigned int t = 0; t < args.numthreads; t++) - thr[t] = new thread(SubgraphThread, t, &graph_data, &graph_vector, &graphnum, &list_mtx, args.graphfilepath + "/"); + thr[t] = new thread(SubgraphThread, t, &graph_data, &graph_vector, &graphnum, &list_mtx, args.graphfilepath + "/", &traveler_lists); for (unsigned int t = 0; t < args.numthreads; t++) thr[t]->join(); for (unsigned int t = 0; t < args.numthreads; t++) delete thr[t]; #else while (graphnum < graph_vector.size()) - { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0); + { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0, &traveler_lists); graphnum += 2; } #endif @@ -168,14 +168,14 @@ else { list *regions; #ifdef threading_enabled // set up for threaded subgraph generation for (unsigned int t = 0; t < args.numthreads; t++) - thr[t] = new thread(SubgraphThread, t, &graph_data, &graph_vector, &graphnum, &list_mtx, args.graphfilepath + "/"); + thr[t] = new thread(SubgraphThread, t, &graph_data, &graph_vector, &graphnum, &list_mtx, args.graphfilepath + "/", &traveler_lists); for (unsigned int t = 0; t < args.numthreads; t++) thr[t]->join(); for (unsigned int t = 0; t < args.numthreads; t++) delete thr[t]; #else while (graphnum < graph_vector.size()) - { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0); + { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0, &traveler_lists); graphnum += 2; } #endif @@ -225,14 +225,14 @@ else { list *regions; #ifdef threading_enabled // set up for threaded subgraph generation for (unsigned int t = 0; t < args.numthreads; t++) - thr[t] = new thread(SubgraphThread, t, &graph_data, &graph_vector, &graphnum, &list_mtx, args.graphfilepath + "/"); + thr[t] = new thread(SubgraphThread, t, &graph_data, &graph_vector, &graphnum, &list_mtx, args.graphfilepath + "/", &traveler_lists); for (unsigned int t = 0; t < args.numthreads; t++) thr[t]->join(); for (unsigned int t = 0; t < args.numthreads; t++) delete thr[t]; #else while (graphnum < graph_vector.size()) - { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0); + { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0, &traveler_lists); graphnum += 2; } #endif @@ -281,14 +281,14 @@ else { list *regions; #ifdef threading_enabled // set up for threaded subgraph generation for (unsigned int t = 0; t < args.numthreads; t++) - thr[t] = new thread(SubgraphThread, t, &graph_data, &graph_vector, &graphnum, &list_mtx, args.graphfilepath + "/"); + thr[t] = new thread(SubgraphThread, t, &graph_data, &graph_vector, &graphnum, &list_mtx, args.graphfilepath + "/", &traveler_lists); for (unsigned int t = 0; t < args.numthreads; t++) thr[t]->join(); for (unsigned int t = 0; t < args.numthreads; t++) delete thr[t]; #else while (graphnum < graph_vector.size()) - { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0); + { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0, &traveler_lists); graphnum += 2; } #endif @@ -321,14 +321,14 @@ else { list *regions; #ifdef threading_enabled // set up for threaded subgraph generation for (unsigned int t = 0; t < args.numthreads; t++) - thr[t] = new thread(SubgraphThread, t, &graph_data, &graph_vector, &graphnum, &list_mtx, args.graphfilepath + "/"); + thr[t] = new thread(SubgraphThread, t, &graph_data, &graph_vector, &graphnum, &list_mtx, args.graphfilepath + "/", &traveler_lists); for (unsigned int t = 0; t < args.numthreads; t++) thr[t]->join(); for (unsigned int t = 0; t < args.numthreads; t++) delete thr[t]; #else while (graphnum < graph_vector.size()) - { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0); + { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0, &traveler_lists); graphnum += 2; } #endif @@ -361,14 +361,14 @@ else { list *regions; #ifdef threading_enabled // set up for threaded subgraph generation for (unsigned int t = 0; t < args.numthreads; t++) - thr[t] = new thread(SubgraphThread, t, &graph_data, &graph_vector, &graphnum, &list_mtx, args.graphfilepath + "/"); + thr[t] = new thread(SubgraphThread, t, &graph_data, &graph_vector, &graphnum, &list_mtx, args.graphfilepath + "/", &traveler_lists); for (unsigned int t = 0; t < args.numthreads; t++) thr[t]->join(); for (unsigned int t = 0; t < args.numthreads; t++) delete thr[t]; #else while (graphnum < graph_vector.size()) - { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0); + { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0, &traveler_lists); graphnum += 2; } #endif diff --git a/siteupdate/cplusplus/siteupdate.cpp b/siteupdate/cplusplus/siteupdate.cpp index 563e570a..bd7ca859 100644 --- a/siteupdate/cplusplus/siteupdate.cpp +++ b/siteupdate/cplusplus/siteupdate.cpp @@ -412,6 +412,12 @@ int main(int argc, char *argv[]) #endif cout << " processed " << traveler_lists.size() << " traveler list files." << endl; traveler_lists.sort(sort_travelers_by_name); + // assign traveler numbers + unsigned int travnum = 0; + for (TravelerList *t : traveler_lists) + { t->traveler_num = travnum; + travnum++; + } //#include "debug/highway_segment_log.cpp" //#include "debug/pioneers.cpp" diff --git a/siteupdate/cplusplus/threads/ReadListThread.cpp b/siteupdate/cplusplus/threads/ReadListThread.cpp index 6f964fa9..f990922e 100644 --- a/siteupdate/cplusplus/threads/ReadListThread.cpp +++ b/siteupdate/cplusplus/threads/ReadListThread.cpp @@ -13,7 +13,10 @@ void ReadListThread(std::list *traveler_ids, std::listpop_front() successful." << std::endl; std::cout << ' ' << tl << std::flush; tl_mtx->unlock(); - traveler_lists->push_back(new TravelerList(tl, route_hash, args, strtok_mtx)); - // deleted on termination of program + TravelerList *t = new TravelerList(tl, route_hash, args, strtok_mtx); + // deleted on termination of program + TravelerList::alltrav_mtx.lock(); + traveler_lists->push_back(t); + TravelerList::alltrav_mtx.unlock(); } } diff --git a/siteupdate/cplusplus/threads/SubgraphThread.cpp b/siteupdate/cplusplus/threads/SubgraphThread.cpp index e9b943f7..7604572e 100644 --- a/siteupdate/cplusplus/threads/SubgraphThread.cpp +++ b/siteupdate/cplusplus/threads/SubgraphThread.cpp @@ -1,4 +1,5 @@ -void SubgraphThread(unsigned int id, HighwayGraph *graph_data, std::vector *graph_vector, size_t *index, std::mutex *mtx, std::string path) +void SubgraphThread(unsigned int id, HighwayGraph *graph_data, std::vector *graph_vector, +size_t *index, std::mutex *mtx, std::string path, std::list *traveler_lists) { //std::cout << "Starting SubgraphThread " << id << std::endl; while (*index < graph_vector->size()) { mtx->lock(); @@ -11,6 +12,6 @@ void SubgraphThread(unsigned int id, HighwayGraph *graph_data, std::vectorunlock(); - graph_data->write_subgraphs_tmg(*graph_vector, path, i, id); + graph_data->write_subgraphs_tmg(*graph_vector, path, i, id, traveler_lists); } } From 8b2c5cdb996a29ec61d1855d1ed5453150eb2d33 Mon Sep 17 00:00:00 2001 From: eric bryant Date: Sun, 7 Apr 2019 11:22:01 -0400 Subject: [PATCH 11/17] C++: traveled subgraph implementation --- .../classes/GraphGeneration/HighwayGraph.cpp | 70 ++++++++++++++++--- .../cplusplus/functions/graph_generation.cpp | 26 +++++-- .../cplusplus/threads/SubgraphThread.cpp | 2 +- 3 files changed, 80 insertions(+), 18 deletions(-) diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp index af15855d..fec80c65 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp @@ -327,6 +327,39 @@ class HighwayGraph return edge_set; } + std::unordered_set matching_traveled_edges(std::unordered_set &mv, GraphListEntry &g) + { // return a set of edges for the traveled graph format, + // optionally restricted by region or system or placeradius + std::unordered_set edge_set; + for (HGVertex *v : mv) + { if (v->visibility < 1) continue; + for (HGEdge *e : v->incident_t_edges) + if (!g.placeradius || g.placeradius->contains_edge(e)) + { bool rg_in_rg = 0; + if (g.regions) for (Region *r : *g.regions) + if (r == e->segment->route->region) + { rg_in_rg = 1; + break; + } + if (!g.regions || rg_in_rg) + { bool system_match = !g.systems; + if (!system_match) + for (std::pair &rs : e->route_names_and_systems) + { bool sys_in_sys = 0; + if (g.systems) for (HighwaySystem *s : *g.systems) + if (s == rs.second) + { sys_in_sys = 1; + break; + } + if (sys_in_sys) system_match = 1; + } + if (system_match) edge_set.insert(e); + } + } + } + return edge_set; + } + // write the entire set of highway data in .tmg format. // The first line is a header specifying // the format and version number, the second line specifying the @@ -460,24 +493,28 @@ class HighwayGraph void write_subgraphs_tmg(std::vector &graph_vector, std::string path, size_t graphnum, unsigned int threadnum, std::list *traveler_lists) { unsigned int cv_count, tv_count; - std::string simplefilename = path+graph_vector[graphnum].filename(); - std::string collapfilename = path+graph_vector[graphnum+1].filename(); - std::ofstream simplefile(simplefilename.data()); - std::ofstream collapfile(collapfilename.data()); + std::ofstream simplefile((path+graph_vector[graphnum].filename()).data()); + std::ofstream collapfile((path+graph_vector[graphnum+1].filename()).data()); + std::ofstream travelfile((path+graph_vector[graphnum+2].filename()).data()); std::unordered_set mv = matching_vertices(graph_vector[graphnum], cv_count, tv_count); std::unordered_set mse = matching_simple_edges(mv, graph_vector[graphnum]); std::unordered_set mce = matching_collapsed_edges(mv, graph_vector[graphnum]); + std::unordered_set mte = matching_traveled_edges(mv, graph_vector[graphnum]); std::cout << graph_vector[graphnum].tag() << '(' << mv.size() << ',' << mse.size() << ") " - << '(' << cv_count << ',' << mce.size() << ") " << std::flush; + << '(' << cv_count << ',' << mce.size() << ") " + << '(' << tv_count << ',' << mte.size() << ") " << std::flush; simplefile << "TMG 1.0 simple\n"; collapfile << "TMG 1.0 collapsed\n"; + travelfile << "TMG 2.0 traveled\n"; simplefile << mv.size() << ' ' << mse.size() << '\n'; collapfile << cv_count << ' ' << mce.size() << '\n'; + travelfile << tv_count << ' ' << mte.size() << '\n'; // write vertices unsigned int sv = 0; unsigned int cv = 0; + unsigned int tv = 0; for (HGVertex *v : mv) { char fstr[43]; sprintf(fstr, " %.15g %.15g", v->lat, v->lng); @@ -485,11 +522,18 @@ class HighwayGraph simplefile << *(v->unique_name) << fstr << '\n'; v->s_vertex_num[threadnum] = sv; sv++; - // visible vertices, for collapsed graph - if (v->visibility == 2) - { collapfile << *(v->unique_name) << fstr << '\n'; - v->c_vertex_num[threadnum] = cv; - cv++; + // visible vertices... + if (v->visibility >= 1) + { // for traveled graph, + travelfile << *(v->unique_name) << fstr << '\n'; + v->t_vertex_num[threadnum] = tv; + tv++; + if (v->visibility == 2) + { // and for collapsed graph + collapfile << *(v->unique_name) << fstr << '\n'; + v->c_vertex_num[threadnum] = cv; + cv++; + } } } // write edges @@ -499,8 +543,14 @@ class HighwayGraph << e->label(graph_vector[graphnum].systems) << '\n'; for (HGEdge *e : mce) collapfile << e->collapsed_tmg_line(graph_vector[graphnum].systems, threadnum) << '\n'; + for (HGEdge *e : mte) + travelfile << e->traveled_tmg_line(graph_vector[graphnum].systems, traveler_lists, threadnum) << '\n'; + // traveler names + for (TravelerList *t : *traveler_lists) + travelfile << t->traveler_name << ' '; simplefile.close(); collapfile.close(); + travelfile.close(); graph_vector[graphnum].vertices = mv.size(); graph_vector[graphnum+1].vertices = cv_count; diff --git a/siteupdate/cplusplus/functions/graph_generation.cpp b/siteupdate/cplusplus/functions/graph_generation.cpp index ed70e02e..937b7cd7 100644 --- a/siteupdate/cplusplus/functions/graph_generation.cpp +++ b/siteupdate/cplusplus/functions/graph_generation.cpp @@ -79,6 +79,8 @@ else { list *regions; 's', 'a', (list*)0, (list*)0, &a); graph_vector.emplace_back(a.base + to_string(a.r) + "-area", a.place + " (" + to_string(a.r) + " mi radius)", 'c', 'a', (list*)0, (list*)0, &a); + graph_vector.emplace_back(a.base + to_string(a.r) + "-area", a.place + " (" + to_string(a.r) + " mi radius)", + 't', 'a', (list*)0, (list*)0, &a); } // write new graph_vector entries to disk #ifdef threading_enabled @@ -92,7 +94,7 @@ else { list *regions; #else while (graphnum < graph_vector.size()) { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0, &traveler_lists); - graphnum += 2; + graphnum += 3; } #endif graph_types.push_back({"area", "Routes Within a Given Radius of a Place", @@ -116,6 +118,8 @@ else { list *regions; 's', 'r', regions, (list*)0, (PlaceRadius*)0); graph_vector.emplace_back(region.code + "-region", region.name + " (" + region.type + ")", 'c', 'r', (list*)0, (list*)0, (PlaceRadius*)0); + graph_vector.emplace_back(region.code + "-region", region.name + " (" + region.type + ")", + 't', 'r', (list*)0, (list*)0, (PlaceRadius*)0); } // write new graph_vector entries to disk #ifdef threading_enabled @@ -129,7 +133,7 @@ else { list *regions; #else while (graphnum < graph_vector.size()) { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0, &traveler_lists); - graphnum += 2; + graphnum += 3; } #endif graph_types.push_back({"region", "Routes Within a Single Region", "These graphs contain all routes currently plotted within the given region."}); @@ -161,6 +165,8 @@ else { list *regions; 's', 's', (list*)0, systems, (PlaceRadius*)0); graph_vector.emplace_back(h->systemname + "-system", h->systemname + " (" + h->fullname + ")", 'c', 's', (list*)0, (list*)0, (PlaceRadius*)0); + graph_vector.emplace_back(h->systemname + "-system", h->systemname + " (" + h->fullname + ")", + 't', 's', (list*)0, (list*)0, (PlaceRadius*)0); } } file.close(); @@ -176,7 +182,7 @@ else { list *regions; #else while (graphnum < graph_vector.size()) { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0, &traveler_lists); - graphnum += 2; + graphnum += 3; } #endif if (h) graph_types.push_back({"system", "Routes Within a Single Highway System", @@ -218,6 +224,7 @@ else { list *regions; } graph_vector.emplace_back(fields[1], fields[0], 's', 'S', (list*)0, systems, (PlaceRadius*)0); graph_vector.emplace_back(fields[1], fields[0], 'c', 'S', (list*)0, (list*)0, (PlaceRadius*)0); + graph_vector.emplace_back(fields[1], fields[0], 't', 'S', (list*)0, (list*)0, (PlaceRadius*)0); delete[] cline; } file.close(); @@ -233,7 +240,7 @@ else { list *regions; #else while (graphnum < graph_vector.size()) { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0, &traveler_lists); - graphnum += 2; + graphnum += 3; } #endif graph_types.push_back({"multisystem", "Routes Within Multiple Highway Systems", "These graphs contain the routes within a set of highway systems."}); @@ -274,6 +281,7 @@ else { list *regions; } graph_vector.emplace_back(fields[1], fields[0], 's', 'R', regions, (list*)0, (PlaceRadius*)0); graph_vector.emplace_back(fields[1], fields[0], 'c', 'R', (list*)0, (list*)0, (PlaceRadius*)0); + graph_vector.emplace_back(fields[1], fields[0], 't', 'R', (list*)0, (list*)0, (PlaceRadius*)0); delete[] cline; } file.close(); @@ -289,7 +297,7 @@ else { list *regions; #else while (graphnum < graph_vector.size()) { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0, &traveler_lists); - graphnum += 2; + graphnum += 3; } #endif graph_types.push_back({"multiregion", "Routes Within Multiple Regions", "These graphs contain the routes within a set of regions."}); @@ -315,6 +323,8 @@ else { list *regions; 's', 'c', regions, (list*)0, (PlaceRadius*)0); graph_vector.emplace_back(c.first + "-country", c.second + " All Routes in Country", 'c', 'c', (list*)0, (list*)0, (PlaceRadius*)0); + graph_vector.emplace_back(c.first + "-country", c.second + " All Routes in Country", + 't', 't', (list*)0, (list*)0, (PlaceRadius*)0); } } // write new graph_vector entries to disk @@ -329,7 +339,7 @@ else { list *regions; #else while (graphnum < graph_vector.size()) { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0, &traveler_lists); - graphnum += 2; + graphnum += 3; } #endif graph_types.push_back({"country", "Routes Within a Single Multi-Region Country", @@ -355,6 +365,8 @@ else { list *regions; 's', 'C', regions, (list*)0, (PlaceRadius*)0); graph_vector.emplace_back(c.first + "-continent", c.second + " All Routes on Continent", 'c', 'C', (list*)0, (list*)0, (PlaceRadius*)0); + graph_vector.emplace_back(c.first + "-continent", c.second + " All Routes on Continent", + 't', 'C', (list*)0, (list*)0, (PlaceRadius*)0); } } // write new graph_vector entries to disk @@ -369,7 +381,7 @@ else { list *regions; #else while (graphnum < graph_vector.size()) { graph_data.write_subgraphs_tmg(graph_vector, args.graphfilepath + "/", graphnum, 0, &traveler_lists); - graphnum += 2; + graphnum += 3; } #endif graph_types.push_back({"continent", "Routes Within a Continent", "These graphs contain the routes on a continent."}); diff --git a/siteupdate/cplusplus/threads/SubgraphThread.cpp b/siteupdate/cplusplus/threads/SubgraphThread.cpp index 7604572e..d56e96f2 100644 --- a/siteupdate/cplusplus/threads/SubgraphThread.cpp +++ b/siteupdate/cplusplus/threads/SubgraphThread.cpp @@ -10,7 +10,7 @@ size_t *index, std::mutex *mtx, std::string path, std::list *trav //std::cout << "Thread " << id << " with graph_vector.size()=" << graph_vector->size() << " & index=" << *index << std::endl; //std::cout << "Thread " << id << " assigned " << graph_vector->at(*index).tag() << std::endl; size_t i = *index; - *index += 2; + *index += 3; mtx->unlock(); graph_data->write_subgraphs_tmg(*graph_vector, path, i, id, traveler_lists); } From f12c775a9b14b674ca35a8c818c9c397840233a8 Mon Sep 17 00:00:00 2001 From: eric bryant Date: Fri, 19 Apr 2019 03:31:41 -0400 Subject: [PATCH 12/17] region-splitting support concurrency sanity checks http://forum.travelmapping.net/index.php?topic=2976.msg13621#msg13621 .list line replacement http://forum.travelmapping.net/index.php?topic=2926.msg13689#msg13689 --- siteupdate/cplusplus/classes/Arguments.cpp | 12 +++- .../cplusplus/classes/ConnectedRoute.cpp | 17 +++++ siteupdate/cplusplus/classes/Route/Route.cpp | 12 ++++ siteupdate/cplusplus/classes/Route/Route.h | 2 + .../classes/TravelerList/TravelerList.cpp | 72 ++++++++++++++----- .../classes/TravelerList/splitregion.cpp | 27 +++++++ .../functions/concurrency_detection.cpp | 69 ++++++++++++++++++ .../cplusplus/functions/crawl_hwy_data.cpp | 9 ++- siteupdate/cplusplus/siteupdate.cpp | 53 ++------------ 9 files changed, 201 insertions(+), 72 deletions(-) create mode 100644 siteupdate/cplusplus/classes/TravelerList/splitregion.cpp create mode 100644 siteupdate/cplusplus/functions/concurrency_detection.cpp diff --git a/siteupdate/cplusplus/classes/Arguments.cpp b/siteupdate/cplusplus/classes/Arguments.cpp index 977a17e7..b37ab7a2 100644 --- a/siteupdate/cplusplus/classes/Arguments.cpp +++ b/siteupdate/cplusplus/classes/Arguments.cpp @@ -11,6 +11,7 @@ class Arguments /* g */ std::string graphfilepath; /* k */ bool skipgraphs; /* n */ std::string nmpmergepath; + /* p */ std::string splitregion, splitregionpath; /* U */ std::list userlist; /* t */ unsigned int numthreads; /* e */ bool errorcheck; @@ -27,6 +28,7 @@ class Arguments /* g */ graphfilepath = "."; /* k */ skipgraphs = 0; /* n */ nmpmergepath = ""; + /* p */ splitregionpath = ""; /* U */ // nothing to do here /* t */ numthreads = 4; /* e */ errorcheck = 0; @@ -52,6 +54,8 @@ class Arguments skipgraphs = 1; else if ( !strcmp(argv[n], "-n") || !strcmp(argv[n], "--nmpmergepath") ) { nmpmergepath = argv[n+1]; n++; } + else if ( !strcmp(argv[n], "-p") || !strcmp(argv[n], "--splitregion") ) { + splitregionpath = argv[n+1]; splitregion = argv[n+2]; n +=2; } else if ( !strcmp(argv[n], "-t") || !strcmp(argv[n], "--numthreads") ) { numthreads = strtol(argv[n+1], 0, 10); n++; } else if ( !strcmp(argv[n], "-e") || !strcmp(argv[n], "--errorcheck") ) @@ -70,8 +74,8 @@ class Arguments { std::cout << "usage: siteupdate.py [-h] [-w HIGHWAYDATAPATH] [-s SYSTEMSFILE]\n"; std::cout << " [-u USERLISTFILEPATH] [-d DATABASENAME] [-l LOGFILEPATH]\n"; std::cout << " [-c CSVSTATFILEPATH] [-g GRAPHFILEPATH] [-k]\n"; - std::cout << " [-n NMPMERGEPATH] [-U USERLIST [USERLIST ...]]\n"; - std::cout << " [-t NUMTHREADS] [-e]\n"; + std::cout << " [-n NMPMERGEPATH] [-p SPLITREGIONPATH SPLITREGION]\n"; + std::cout << " [-U USERLIST [USERLIST ...]] [-t NUMTHREADS] [-e]\n"; std::cout << "\n"; std::cout << "Create SQL, stats, graphs, and log files from highway and user data for the\n"; std::cout << "Travel Mapping project.\n"; @@ -98,6 +102,10 @@ class Arguments std::cout << " -n NMPMERGEPATH, --nmpmergepath NMPMERGEPATH\n"; std::cout << " Path to write data with NMPs merged (generated only if\n"; std::cout << " specified)\n"; + std::cout << " -p SPLITREGIONPATH SPLITREGION, --splitregion SPLITREGIONPATH SPLITREGION\n"; + std::cout << " Path to logs & .lists for a specific...\n"; + std::cout << " Region being split into rubregions.\n"; + std::cout << " For Development.\n"; std::cout << " -U USERLIST [USERLIST ...], --userlist USERLIST [USERLIST ...]\n"; std::cout << " For Development: list of users to use in dataset\n"; std::cout << " -t NUMTHREADS, --numthreads NUMTHREADS\n"; diff --git a/siteupdate/cplusplus/classes/ConnectedRoute.cpp b/siteupdate/cplusplus/classes/ConnectedRoute.cpp index 862f581a..34a9a28f 100644 --- a/siteupdate/cplusplus/classes/ConnectedRoute.cpp +++ b/siteupdate/cplusplus/classes/ConnectedRoute.cpp @@ -74,6 +74,7 @@ class ConnectedRoute { Route *root = route_by_root(token, route_list); if (!root) el.add_error("Could not find Route matching root " + std::string(token) + " in system " + system->systemname + '.'); else { roots.push_back(root); + root->con_route = this; // save order of route in connected route root->rootOrder = rootOrder; } @@ -107,4 +108,20 @@ class ConnectedRoute if (!groupname.empty()) ans += " (" + groupname + ")"; return ans; } + + std::string list_lines(int pos, int len, std::string newline, size_t indent) + { // return .list file lines marking (len) consecutive + // segments, starting at waypoint (pos) segments into route + //std::cout << "\nDEBUG: list_lines for " << readable_name() << " (" << roots.size() << " connected root(s))" << std::endl; + std::string lines; + for (Route *r : roots) + { //std::cout << "DEBUG: [" << pos << " + " << len << " = " << pos+len << "] " << r->str() << std::endl; + std::string line = std::string(indent, ' ') + r->list_line(pos, pos+len); + if (line.size() > indent) lines += line + newline; + pos -= r->segment_list.size(); + } + // strip final newline + while (lines.back() == '\n' || lines.back() == '\r') lines.pop_back(); + return lines; + } }; diff --git a/siteupdate/cplusplus/classes/Route/Route.cpp b/siteupdate/cplusplus/classes/Route/Route.cpp index 3e076e6d..7eaf704a 100644 --- a/siteupdate/cplusplus/classes/Route/Route.cpp +++ b/siteupdate/cplusplus/classes/Route/Route.cpp @@ -5,6 +5,7 @@ std::mutex Route::awf_mtx; Route::Route(std::string &line, HighwaySystem *sys, ErrorList &el, std::list &all_regions) { /* initialize object from a .csv file line, but do not yet read in waypoint file */ + con_route = 0; mileage = 0; rootOrder = -1; // order within connected route if (line.back() == 0x0D) line.erase(line.end()-1); // trim DOS newlines @@ -180,6 +181,17 @@ bool Route::is_valid() return 1; } +std::string Route::list_line(int beg, int end) +{ /* Return a .list file line from (beg) to (end), + these being indices to the point_list vector. + These values can be "out-of-bounds" when getting lines + for connected routes. If so, truncate or return "". */ + if (beg >= int(point_list.size()) || end <= 0) return ""; + if (end >= int(point_list.size())) end = point_list.size()-1; + if (beg < 0) beg = 0; + return readable_name() + " " + point_list[beg]->label + " " + point_list[end]->label; +} + void Route::write_nmp_merged(std::string filename) { mkdir(filename.data(), 0777); filename += "/" + system->systemname; diff --git a/siteupdate/cplusplus/classes/Route/Route.h b/siteupdate/cplusplus/classes/Route/Route.h index 102ac87b..006079cd 100644 --- a/siteupdate/cplusplus/classes/Route/Route.h +++ b/siteupdate/cplusplus/classes/Route/Route.h @@ -39,6 +39,7 @@ class Route public: HighwaySystem *system; Region *region; + ConnectedRoute *con_route; std::string route; std::string banner; std::string abbrev; @@ -70,5 +71,6 @@ class Route std::string name_no_abbrev(); double clinched_by_traveler(TravelerList *); bool is_valid(); + std::string list_line(int, int); void write_nmp_merged(std::string); }; diff --git a/siteupdate/cplusplus/classes/TravelerList/TravelerList.cpp b/siteupdate/cplusplus/classes/TravelerList/TravelerList.cpp index 00189431..690c30eb 100644 --- a/siteupdate/cplusplus/classes/TravelerList/TravelerList.cpp +++ b/siteupdate/cplusplus/classes/TravelerList/TravelerList.cpp @@ -38,10 +38,13 @@ class TravelerList traveler_name = travname.substr(0, travname.size()-5); // strip ".list" from end of travname std::string filename = args->logfilepath+"/users/"+traveler_name+".log"; std::ofstream log(filename.data()); + std::ofstream splist; + if (args->splitregionpath != "") splist.open((args->splitregionpath+"/list_files/"+travname).data()); time_t StartTime = time(0); log << "Log file created at: " << ctime(&StartTime); filename = args->userlistfilepath+"/"+travname; std::vector lines; + std::vector endlines; std::ifstream file(filename.data()); // we can't getline here because it only allows one delimiter, and we need two; '\r' and '\n'. // at least one .list file contains newlines using only '\r' (0x0D): @@ -53,13 +56,35 @@ class TravelerList file.read(listdata, listdatasize); listdata[listdatasize] = 0; // add null terminator file.close(); - strtok_mtx->lock(); - for (char *token = strtok(listdata, "\r\n"); token; token = strtok(0, "\r\n") ) lines.push_back(token); - strtok_mtx->unlock(); + + // get canonical newline for writing splitregion .list files + std::string newline; + unsigned long c = 0; + while (listdata[c] != '\r' && listdata[c] != '\n' && c < listdatasize) c++; + if (listdata[c] == '\r') + if (listdata[c+1] == '\n') newline = "\r\n"; + else newline = "\r"; + else if (listdata[c] == '\n') newline = "\n"; + // Use CRLF as failsafe if .list file contains no newlines. + else newline = "\r\n"; + + // separate listdata into series of lines & newlines + size_t spn = 0; + for (char *c = listdata; *c; c += spn) + { endlines.push_back(""); + spn = strcspn(c, "\r\n"); + while (c[spn] == '\r' || c[spn] == '\n') + { endlines.back().push_back(c[spn]); + c[spn] = 0; + spn++; + } + lines.push_back(c); + } lines.push_back(listdata+listdatasize+1); // add a dummy "past-the-end" element to make lines[l+1]-2 work for (unsigned int l = 0; l < lines.size()-1; l++) - { // strip whitespace + { std::string orig_line(lines[l]); + // strip whitespace while (lines[l][0] == ' ' || lines[l][0] == '\t') lines[l]++; char * endchar = lines[l+1]-2; // -2 skips over the 0 inserted by strtok if (*endchar == 0) endchar--; // skip back one more for CRLF cases FIXME what about lines followed by blank lines? @@ -67,9 +92,12 @@ class TravelerList { *endchar = 0; endchar--; } - std::string origline(lines[l]); + std::string trim_line(lines[l]); // ignore empty or "comment" lines - if (lines[l][0] == 0 || lines[l][0] == '#') continue; + if (lines[l][0] == 0 || lines[l][0] == '#') + { splist << orig_line << endlines[l]; + continue; + } // process fields in line std::vector fields; strtok_mtx->lock(); @@ -78,9 +106,10 @@ class TravelerList if (fields.size() != 4) // OK if 5th field exists and starts with # if (fields.size() < 5 || fields[4][0] != '#') - { for (size_t c = 0; c < origline.size(); c++) - if (origline[c] < 0x20 || origline[c] >= 0x7F) origline[c] = '?'; - log << "Incorrect format line: " << origline << '\n'; + { for (size_t c = 0; c < trim_line.size(); c++) + if (trim_line[c] < 0x20 || trim_line[c] >= 0x7F) trim_line[c] = '?'; + log << "Incorrect format line: " << trim_line << '\n'; + splist << orig_line << endlines[l]; continue; } @@ -91,11 +120,12 @@ class TravelerList for (std:: string a : r->alt_route_names) if (route_entry == lower(a)) { log << "Note: deprecated route name " << fields[1] - << " -> canonical name " << r->list_entry_name() << " in line " << origline << '\n'; + << " -> canonical name " << r->list_entry_name() << " in line " << trim_line << '\n'; break; } if (r->system->devel()) - { log << "Ignoring line matching highway in system in development: " << origline << '\n'; + { log << "Ignoring line matching highway in system in development: " << trim_line << '\n'; + splist << orig_line << endlines[l]; continue; } // r is a route match, r.root is our root, and we need to find @@ -136,14 +166,15 @@ class TravelerList } if (canonical_waypoints.size() != 2) { bool invalid_char = 0; - for (size_t c = 0; c < origline.size(); c++) - if (origline[c] < 0x20 || origline[c] >= 0x7F) - { origline[c] = '?'; + for (size_t c = 0; c < trim_line.size(); c++) + if (trim_line[c] < 0x20 || trim_line[c] >= 0x7F) + { trim_line[c] = '?'; invalid_char = 1; } - log << "Waypoint label(s) not found in line: " << origline; + log << "Waypoint label(s) not found in line: " << trim_line; if (invalid_char) log << " [line contains invalid character(s)]"; log << '\n'; + splist << orig_line << endlines[l]; } else { list_entries.emplace_back(/**line,*/ r, canonical_waypoint_indices[0], canonical_waypoint_indices[1]); // find the segments we just matched and store this traveler with the @@ -154,23 +185,26 @@ class TravelerList hs->add_clinched_by(this); clinched_segments.insert(hs); } + #include "splitregion.cpp" } } catch (const std::out_of_range& oor) { bool invalid_char = 0; - for (size_t c = 0; c < origline.size(); c++) - if (origline[c] < 0x20 || origline[c] >= 0x7F) - { origline[c] = '?'; + for (size_t c = 0; c < trim_line.size(); c++) + if (trim_line[c] < 0x20 || trim_line[c] >= 0x7F) + { trim_line[c] = '?'; invalid_char = 1; } - log << "Unknown region/highway combo in line: " << origline; + log << "Unknown region/highway combo in line: " << trim_line; if (invalid_char) log << " [line contains invalid character(s)]"; log << '\n'; + splist << orig_line << endlines[l]; } } delete[] listdata; log << "Processed " << list_entries.size() << " good lines marking " << clinched_segments.size() << " segments traveled.\n"; log.close(); + splist.close(); } /* Return active mileage across all regions */ diff --git a/siteupdate/cplusplus/classes/TravelerList/splitregion.cpp b/siteupdate/cplusplus/classes/TravelerList/splitregion.cpp new file mode 100644 index 00000000..e2a38dfe --- /dev/null +++ b/siteupdate/cplusplus/classes/TravelerList/splitregion.cpp @@ -0,0 +1,27 @@ +// new .list lines for region split-ups +if (args->splitregion == upper(fields[0])) +{ // first, comment out original line + splist << "##### " << orig_line << newline; + HighwaySegment *orig_hs = r->segment_list[canonical_waypoint_indices[0]]; + HighwaySegment *new_hs = 0; + if (!orig_hs->concurrent) + std::cout << "ERROR: " << orig_hs->str() << " not concurrent" << std::endl; + else { size_t count = 0; + // find concurrent segment with same name in different region + for (HighwaySegment *cs : *(orig_hs->concurrent)) + if (cs->route->name_no_abbrev() == r->name_no_abbrev() && cs->route->region != r->region) + { count++; + new_hs = cs; + } + if (!new_hs) std::cout << "ERROR: concurrent segment not found for " << orig_hs->str() << std::endl; + else { if (count > 1) std::cout << "DEBUG: multiple matches found for " << orig_hs->str() << std::endl; + // get lines from associated connected route. + // assumption: each chopped route in old full region corresponds 1:1 to a connected route in new chopped regions + splist << new_hs->route->con_route->list_lines(canonical_waypoint_indices[0], + canonical_waypoint_indices[1] - + canonical_waypoint_indices[0], + newline, 2) << endlines[l]; + } + } +} +else splist << orig_line << endlines[l]; diff --git a/siteupdate/cplusplus/functions/concurrency_detection.cpp b/siteupdate/cplusplus/functions/concurrency_detection.cpp new file mode 100644 index 00000000..8c17669c --- /dev/null +++ b/siteupdate/cplusplus/functions/concurrency_detection.cpp @@ -0,0 +1,69 @@ +// concurrency detection -- will augment our structure with list of concurrent +// segments with each segment (that has a concurrency) +cout << et.et() << "Concurrent segment detection." << flush; +filename = args.logfilepath+"/concurrencies.log"; +ofstream concurrencyfile(filename.data()); +timestamp = time(0); +concurrencyfile << "Log file created at: " << ctime(×tamp); +for (HighwaySystem *h : highway_systems) +{ cout << '.' << flush; + for (Route &r : h->route_list) + for (HighwaySegment *s : r.segment_list) + if (s->waypoint1->colocated && s->waypoint2->colocated) + for ( Waypoint *w1 : *(s->waypoint1->colocated) ) + if (w1->route->root != r.root) //FIXME: compare route objects directly, using pointers. + // Route is the odd one out anyway, being accessed by value, with copy ctors... Speed increase? + for ( Waypoint *w2 : *(s->waypoint2->colocated) ) + if (w1->route->root == w2->route->root) //FIXME, same thing + { HighwaySegment *other = w1->route->find_segment_by_waypoints(w1,w2); + if (other) + if (!s->concurrent) + { s->concurrent = new list; + // deleted on termination of program + other->concurrent = s->concurrent; + s->concurrent->push_back(s); + s->concurrent->push_back(other); + concurrencyfile << "New concurrency [" << s->str() << "][" << other->str() << "] (" << s->concurrent->size() << ")\n"; + } + else + { other->concurrent = s->concurrent; + std::list::iterator it = s->concurrent->begin(); //FIXME + while (it != s->concurrent->end() && *it != other) it++; //see HighwaySegment.h + if (it == s->concurrent->end()) + { s->concurrent->push_back(other); + //concurrencyfile << "Added concurrency [" << s->str() << "]-[" \ + << other->str() << "] (" << s->concurrent->size() << ")\n"; + concurrencyfile << "Extended concurrency "; + for (HighwaySegment *x : *(s->concurrent)) + concurrencyfile << '[' << x->str() << ']'; + concurrencyfile << " (" << s->concurrent->size() << ")\n"; + } + } + } + // see https://github.com/TravelMapping/DataProcessing/issues/137 + // changes not yet implemented in either the original Python or this C++ version. +} +cout << "!\n"; + +// When splitting a region, perform a sanity check on concurrencies in its systems +if (args.splitregion != "") +{ for (HighwaySystem *h : highway_systems) + { if (splitsystems.find(h->systemname) == splitsystems.end()) continue; + ofstream fralog; + if (args.splitregionpath != "") fralog.open((args.splitregionpath + "/logs/" + h->systemname + "-concurrencies.log").data()); + for (Route &r : h->route_list) + { if (r.region->code.substr(0, args.splitregion.size()) != args.splitregion) continue; + for (HighwaySegment *s : r.segment_list) + if (!s->concurrent) + fralog << s->str() << " has no concurrencies\n"; + //TODO: check for concurrent same designated+bannered route in different region + else if (s->concurrent->size() % 2) + { fralog << "Odd number of concurrencies:\n"; + for (HighwaySegment *cs : *(s->concurrent)) + fralog << '\t' << cs->str() << '\n'; + } + + } + fralog.close(); + } +} diff --git a/siteupdate/cplusplus/functions/crawl_hwy_data.cpp b/siteupdate/cplusplus/functions/crawl_hwy_data.cpp index 4824d404..6e60bf0f 100644 --- a/siteupdate/cplusplus/functions/crawl_hwy_data.cpp +++ b/siteupdate/cplusplus/functions/crawl_hwy_data.cpp @@ -1,4 +1,4 @@ -void crawl_hwy_data(std::string path, std::unordered_set &all_wpt_files) +void crawl_hwy_data(std::string path, std::unordered_set &all_wpt_files, std::unordered_set &splitsystems, std::string &splitregion, bool get_ss) { DIR *dir; dirent *ent; struct stat buf; @@ -8,7 +8,12 @@ void crawl_hwy_data(std::string path, std::unordered_set &all_wpt_f stat(entry.data(), &buf); if (S_ISDIR(buf.st_mode)) { if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..") && strcmp(ent->d_name, "_boundaries")) - crawl_hwy_data(entry, all_wpt_files); + { if (get_ss) + { splitsystems.insert(ent->d_name); + splitsystems.insert(std::string(ent->d_name)+'r'); + } + crawl_hwy_data(entry, all_wpt_files, splitsystems, splitregion, splitregion==ent->d_name); + } } else if (entry.substr(entry.size()-4) == ".wpt") all_wpt_files.insert(entry); diff --git a/siteupdate/cplusplus/siteupdate.cpp b/siteupdate/cplusplus/siteupdate.cpp index bd7ca859..caa4539e 100644 --- a/siteupdate/cplusplus/siteupdate.cpp +++ b/siteupdate/cplusplus/siteupdate.cpp @@ -275,8 +275,8 @@ int main(int argc, char *argv[]) // that do not have a .csv file entry that causes them to be // read into the data cout << et.et() << "Finding all .wpt files. " << flush; - unordered_set all_wpt_files; - crawl_hwy_data(args.highwaydatapath+"/hwy_data", all_wpt_files); + unordered_set all_wpt_files, splitsystems; + crawl_hwy_data(args.highwaydatapath+"/hwy_data", all_wpt_files, splitsystems, args.splitregion, 0); cout << all_wpt_files.size() << " files found." << endl; // For finding colocated Waypoints and concurrent segments, we have @@ -382,6 +382,8 @@ int main(int argc, char *argv[]) #endif } + #include "functions/concurrency_detection.cpp" + // Create hash table for faster lookup of routes by list file name cout << et.et() << "Creating route hash table for list processing:" << endl; unordered_map route_hash; @@ -580,53 +582,6 @@ int main(int argc, char *argv[]) unusedfile.close(); - // concurrency detection -- will augment our structure with list of concurrent - // segments with each segment (that has a concurrency) - cout << et.et() << "Concurrent segment detection." << flush; - filename = args.logfilepath+"/concurrencies.log"; - ofstream concurrencyfile(filename.data()); - timestamp = time(0); - concurrencyfile << "Log file created at: " << ctime(×tamp); - for (HighwaySystem *h : highway_systems) - { cout << '.' << flush; - for (Route &r : h->route_list) - for (HighwaySegment *s : r.segment_list) - if (s->waypoint1->colocated && s->waypoint2->colocated) - for ( Waypoint *w1 : *(s->waypoint1->colocated) ) - if (w1->route->root != r.root) //FIXME: compare route objects directly, using pointers. - // Route is the odd one out anyway, being accessed by value, with copy ctors... Speed increase? - for ( Waypoint *w2 : *(s->waypoint2->colocated) ) - if (w1->route->root == w2->route->root) //FIXME, same thing - { HighwaySegment *other = w1->route->find_segment_by_waypoints(w1,w2); - if (other) - if (!s->concurrent) - { s->concurrent = new list; - // deleted on termination of program - other->concurrent = s->concurrent; - s->concurrent->push_back(s); - s->concurrent->push_back(other); - concurrencyfile << "New concurrency [" << s->str() << "][" << other->str() << "] (" << s->concurrent->size() << ")\n"; - } - else - { other->concurrent = s->concurrent; - std::list::iterator it = s->concurrent->begin(); //FIXME - while (it != s->concurrent->end() && *it != other) it++; //see HighwaySegment.h - if (it == s->concurrent->end()) - { s->concurrent->push_back(other); - //concurrencyfile << "Added concurrency [" << s->str() << "]-[" \ - << other->str() << "] (" << s->concurrent->size() << ")\n"; - concurrencyfile << "Extended concurrency "; - for (HighwaySegment *x : *(s->concurrent)) - concurrencyfile << '[' << x->str() << ']'; - concurrencyfile << " (" << s->concurrent->size() << ")\n"; - } - } - } - // see https://github.com/TravelMapping/DataProcessing/issues/137 - // changes not yet implemented in either the original Python or this C++ version. - } - cout << "!\n"; - // now augment any traveler clinched segments for concurrencies cout << et.et() << "Augmenting travelers for detected concurrent segments." << flush; //#include "debug/concurrency_augments.cpp" From 767913f992ee91914513022e31509e94a84d2d5a Mon Sep 17 00:00:00 2001 From: eric bryant Date: Fri, 19 Apr 2019 14:40:14 -0400 Subject: [PATCH 13/17] C++: concurrency detection minor speed improvement --- siteupdate/cplusplus/functions/concurrency_detection.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/siteupdate/cplusplus/functions/concurrency_detection.cpp b/siteupdate/cplusplus/functions/concurrency_detection.cpp index 8c17669c..0ead9263 100644 --- a/siteupdate/cplusplus/functions/concurrency_detection.cpp +++ b/siteupdate/cplusplus/functions/concurrency_detection.cpp @@ -11,10 +11,9 @@ for (HighwaySystem *h : highway_systems) for (HighwaySegment *s : r.segment_list) if (s->waypoint1->colocated && s->waypoint2->colocated) for ( Waypoint *w1 : *(s->waypoint1->colocated) ) - if (w1->route->root != r.root) //FIXME: compare route objects directly, using pointers. - // Route is the odd one out anyway, being accessed by value, with copy ctors... Speed increase? + if (w1->route != &r) for ( Waypoint *w2 : *(s->waypoint2->colocated) ) - if (w1->route->root == w2->route->root) //FIXME, same thing + if (w1->route == w2->route) { HighwaySegment *other = w1->route->find_segment_by_waypoints(w1,w2); if (other) if (!s->concurrent) From 1bb34adf288117c9d4f2c5451d206089b707bd65 Mon Sep 17 00:00:00 2001 From: eric bryant Date: Fri, 19 Apr 2019 15:17:50 -0400 Subject: [PATCH 14/17] region-splitting: 1 more concurrency sanity check --- .../functions/concurrency_detection.cpp | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/siteupdate/cplusplus/functions/concurrency_detection.cpp b/siteupdate/cplusplus/functions/concurrency_detection.cpp index 0ead9263..907374bc 100644 --- a/siteupdate/cplusplus/functions/concurrency_detection.cpp +++ b/siteupdate/cplusplus/functions/concurrency_detection.cpp @@ -53,15 +53,21 @@ if (args.splitregion != "") for (Route &r : h->route_list) { if (r.region->code.substr(0, args.splitregion.size()) != args.splitregion) continue; for (HighwaySegment *s : r.segment_list) - if (!s->concurrent) - fralog << s->str() << " has no concurrencies\n"; - //TODO: check for concurrent same designated+bannered route in different region - else if (s->concurrent->size() % 2) - { fralog << "Odd number of concurrencies:\n"; - for (HighwaySegment *cs : *(s->concurrent)) - fralog << '\t' << cs->str() << '\n'; - } - + if (!s->concurrent) + fralog << s->str() << " has no concurrencies\n"; + else if (s->concurrent->size() % 2) + { fralog << "Odd number of concurrencies:\n"; + for (HighwaySegment *cs : *(s->concurrent)) + fralog << '\t' << cs->str() << '\n'; + } + else { // check for concurrent segment with same name+banner in different region + unsigned int matches = 0; + for (HighwaySegment *cs : *(s->concurrent)) + if (cs->route->name_no_abbrev() == s->route->name_no_abbrev() && cs->route->region != s->route->region) + matches++; + if (matches != 1) + fralog << matches << " concurrent segments with same name+banner in different region: " << s->str() << '\n'; + } } fralog.close(); } From 58cc001cdb730601eaa93a1c6737d4850b600d9c Mon Sep 17 00:00:00 2001 From: eric bryant Date: Sat, 20 Apr 2019 02:32:43 -0400 Subject: [PATCH 15/17] multisystem & multiregion graph generation cleanup --- .../cplusplus/functions/graph_generation.cpp | 36 +++++++------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/siteupdate/cplusplus/functions/graph_generation.cpp b/siteupdate/cplusplus/functions/graph_generation.cpp index 937b7cd7..750f33d4 100644 --- a/siteupdate/cplusplus/functions/graph_generation.cpp +++ b/siteupdate/cplusplus/functions/graph_generation.cpp @@ -210,18 +210,12 @@ else { list *regions; } systems = new list; // deleted on termination of program - list selected_systems; - //FIXME rewrite this whole bit to be more compact - for(char* token = strtok(fields[2], ","); token; token = strtok(0, ",")) selected_systems.push_back(token); - for (HighwaySystem *h : highway_systems) - { bool sys_sel = 0; - for (string &s : selected_systems) - if (s == h->systemname) - { sys_sel = 1; - break; - } - if (sys_sel) systems->push_back(h); - } + for(char* s = strtok(fields[2], ","); s; s = strtok(0, ",")) + for (HighwaySystem *h : highway_systems) + if (s == h->systemname) + { systems->push_back(h); + break; + } graph_vector.emplace_back(fields[1], fields[0], 's', 'S', (list*)0, systems, (PlaceRadius*)0); graph_vector.emplace_back(fields[1], fields[0], 'c', 'S', (list*)0, (list*)0, (PlaceRadius*)0); graph_vector.emplace_back(fields[1], fields[0], 't', 'S', (list*)0, (list*)0, (PlaceRadius*)0); @@ -267,18 +261,12 @@ else { list *regions; } regions = new list; // deleted on termination of program - list selected_regions; - //FIXME rewrite this whole bit to be more compact - for(char* token = strtok(fields[2], ","); token; token = strtok(0, ",")) selected_regions.push_back(token); - for (Region &r : all_regions) - { bool rg_sel = 0; - for (string &rg : selected_regions) - if (rg == r.code) - { rg_sel = 1; - break; - } - if (rg_sel && r.active_preview_mileage) regions->push_back(&r); - } + for(char* rg = strtok(fields[2], ","); rg; rg = strtok(0, ",")) + for (Region &r : all_regions) + if (rg == r.code) + { regions->push_back(&r); + break; + } graph_vector.emplace_back(fields[1], fields[0], 's', 'R', regions, (list*)0, (PlaceRadius*)0); graph_vector.emplace_back(fields[1], fields[0], 'c', 'R', (list*)0, (list*)0, (PlaceRadius*)0); graph_vector.emplace_back(fields[1], fields[0], 't', 'R', (list*)0, (list*)0, (PlaceRadius*)0); From 9b2791b297880aa53e6e8a54d8b15bdc4390fe37 Mon Sep 17 00:00:00 2001 From: eric bryant Date: Sat, 20 Apr 2019 13:21:00 -0400 Subject: [PATCH 16/17] bugfix: subgraphs restricted by region AND system Not currently something that shows up in the real world, but should still be fixed. https://github.com/TravelMapping/DataProcessing/issues/207 --- .../classes/GraphGeneration/HighwayGraph.cpp | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp index fec80c65..1e3e0eb5 100644 --- a/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp +++ b/siteupdate/cplusplus/classes/GraphGeneration/HighwayGraph.cpp @@ -216,13 +216,15 @@ class HighwayGraph // determine which vertices are within our region(s) and/or system(s) if (g.regions) - { vertex_set = rg_vertex_set; if (g.systems) - // both regions & systems populated: vertex_set is + { // both regions & systems populated: vertex_set is // intersection of rg_vertex_set & sys_vertex_set for (HGVertex *v : sys_vertex_set) - vertex_set.erase(v); - } + if (rg_vertex_set.find(v) != rg_vertex_set.end()) + vertex_set.insert(v); + } + else // only regions populated + vertex_set = rg_vertex_set; else if (g.systems) // only systems populated vertex_set = sys_vertex_set; @@ -265,13 +267,15 @@ class HighwayGraph // determine which edges are within our region(s) and/or system(s) if (g.regions) - { edge_set = rg_edge_set; if (g.systems) - // both regions & systems populated: edge_set is + { // both regions & systems populated: edge_set is // intersection of rg_edge_set & sys_edge_set - for (HGEdge *v : sys_edge_set) - edge_set.erase(v); - } + for (HGEdge *e : sys_edge_set) + if (rg_edge_set.find(e) != rg_edge_set.end()) + edge_set.insert(e); + } + else // only regions populated + edge_set = rg_edge_set; else if (g.systems) // only systems populated edge_set = sys_edge_set; From fd2157bf1a7233a82ce5c698503fe5abd6581c2c Mon Sep 17 00:00:00 2001 From: eric bryant Date: Sat, 20 Apr 2019 15:07:33 -0400 Subject: [PATCH 17/17] argument-parsing robustness --- siteupdate/cplusplus/classes/Arguments.cpp | 34 ++++++++++------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/siteupdate/cplusplus/classes/Arguments.cpp b/siteupdate/cplusplus/classes/Arguments.cpp index b37ab7a2..bedf62c6 100644 --- a/siteupdate/cplusplus/classes/Arguments.cpp +++ b/siteupdate/cplusplus/classes/Arguments.cpp @@ -1,5 +1,3 @@ -//FIXME: argv[n+1] can smash the stack. -//FIXME: Try breaking --numthreads with garbage arguments class Arguments { public: /* w */ std::string highwaydatapath; @@ -13,7 +11,7 @@ class Arguments /* n */ std::string nmpmergepath; /* p */ std::string splitregion, splitregionpath; /* U */ std::list userlist; - /* t */ unsigned int numthreads; + /* t */ int numthreads; /* e */ bool errorcheck; /* h */ bool help; @@ -36,33 +34,33 @@ class Arguments // parsing for (unsigned int n = 1; n < argc; n++) - { if ( !strcmp(argv[n], "-w") || !strcmp(argv[n], "--highwaydatapath") ) { + { if ( n+1 < argc && !strcmp(argv[n], "-w") || !strcmp(argv[n], "--highwaydatapath") ) { highwaydatapath = argv[n+1]; n++; } - else if ( !strcmp(argv[n], "-s") || !strcmp(argv[n], "--systemsfile") ) { + else if ( n+1 < argc && !strcmp(argv[n], "-s") || !strcmp(argv[n], "--systemsfile") ) { systemsfile = argv[n+1]; n++; } - else if ( !strcmp(argv[n], "-u") || !strcmp(argv[n], "--userlistfilepath") ) { + else if ( n+1 < argc && !strcmp(argv[n], "-u") || !strcmp(argv[n], "--userlistfilepath") ) { userlistfilepath = argv[n+1]; n++; } - else if ( !strcmp(argv[n], "-d") || !strcmp(argv[n], "--databasename") ) { + else if ( n+1 < argc && !strcmp(argv[n], "-d") || !strcmp(argv[n], "--databasename") ) { databasename = argv[n+1]; n++; } - else if ( !strcmp(argv[n], "-l") || !strcmp(argv[n], "--logfilepath") ) { + else if ( n+1 < argc && !strcmp(argv[n], "-l") || !strcmp(argv[n], "--logfilepath") ) { logfilepath = argv[n+1]; n++; } - else if ( !strcmp(argv[n], "-c") || !strcmp(argv[n], "--csvstatfilepath") ) { + else if ( n+1 < argc && !strcmp(argv[n], "-c") || !strcmp(argv[n], "--csvstatfilepath") ) { csvstatfilepath = argv[n+1]; n++; } - else if ( !strcmp(argv[n], "-g") || !strcmp(argv[n], "--graphfilepath") ) { + else if ( n+1 < argc && !strcmp(argv[n], "-g") || !strcmp(argv[n], "--graphfilepath") ) { graphfilepath = argv[n+1]; n++; } - else if ( !strcmp(argv[n], "-k") || !strcmp(argv[n], "--skipgraphs") ) + else if ( !strcmp(argv[n], "-k") || !strcmp(argv[n], "--skipgraphs") ) skipgraphs = 1; - else if ( !strcmp(argv[n], "-n") || !strcmp(argv[n], "--nmpmergepath") ) { + else if ( n+1 < argc && !strcmp(argv[n], "-n") || !strcmp(argv[n], "--nmpmergepath") ) { nmpmergepath = argv[n+1]; n++; } - else if ( !strcmp(argv[n], "-p") || !strcmp(argv[n], "--splitregion") ) { + else if ( n+2 < argc && !strcmp(argv[n], "-p") || !strcmp(argv[n], "--splitregion") ) { splitregionpath = argv[n+1]; splitregion = argv[n+2]; n +=2; } - else if ( !strcmp(argv[n], "-t") || !strcmp(argv[n], "--numthreads") ) { - numthreads = strtol(argv[n+1], 0, 10); n++; } - else if ( !strcmp(argv[n], "-e") || !strcmp(argv[n], "--errorcheck") ) + else if ( n+1 < argc && !strcmp(argv[n], "-t") || !strcmp(argv[n], "--numthreads") ) { + numthreads = strtol(argv[n+1], 0, 10); n++; if (numthreads<1) numthreads=1; } + else if ( !strcmp(argv[n], "-e") || !strcmp(argv[n], "--errorcheck") ) errorcheck = 1; - else if ( !strcmp(argv[n], "-h") || !strcmp(argv[n], "--help") ) { + else if ( !strcmp(argv[n], "-h") || !strcmp(argv[n], "--help") ) { help = 1; show_help(); } - else if ( !strcmp(argv[n], "-U") || !strcmp(argv[n], "--userlist") ) + else if ( n+1 < argc && !strcmp(argv[n], "-U") || !strcmp(argv[n], "--userlist") ) while (n+1 < argc && argv[n+1][0] != '-') { userlist.push_back(argv[n+1]); n++;