340 likes | 356 Views
This library provides functionality and performance improvements for the Street Map application in Milestone 1, including map loading, closing, and querying street segments and intersections.
E N D
Milestone 1 at a Glance Main Executable Streets Database Library Tester Executable Street Map Library
Milestone 1 at a Glance Cannot Modify! Main Executable Streets Database Library Tester Executable Street Map Library
Milestone 1 at a Glance Already Implemented Cannot Modify! Main Executable To be implemented load_map close_map Streets Database Library Tester Executable Street Map Library load_map close_map
Milestone 1 at a Glance Already Implemented Cannot Modify! Main Executable To be implemented load_map close_map Streets Database Library Tester Executable Street Map Library load_map Load, close, queries, etc. queries close_map
What you will need… • To read the handout • Seriously… • At least one global variable (to pass performance tests) • Why? • Containers from the STL • std::vector, std::list • std::map, std::unordered_map, std::multimap • Which containers should we choose?
What you are given… #include "m1.h“ #include "StreetsDatabaseAPI.h“ boolload_map(std::string map_path){ boolload_successful=false; //Load your map related data structures here returnload_successful; } voidclose_map(){ //Clean-up your map related data structures here }
Recommended Steps for m1 • Compile • Run ece297exercise 1
Recommended Steps for m1 • Compile • Run ece297exercise 1 /cad2/ece297s/public//m1/tests/m1_func_intersection_toronto_canada_public.cpp:185: undefined reference to `find_intersection_street_names(int)' /cad2/ece297s/public//m1/tests/m1_func_intersection_toronto_canada_public.cpp:190: undefined reference to `find_intersection_street_names(int)' /cad2/ece297s/public//m1/tests/m1_func_intersection_toronto_canada_public.cpp:195: undefined reference to `find_intersection_street_names(int)' /cad2/ece297s/public//m1/tests/m1_func_intersection_toronto_canada_public.cpp:200: undefined reference to `find_intersection_street_names(int)' /cad2/ece297s/public//m1/tests/m1_func_intersection_toronto_canada_public.cpp:205: undefined referenceto `find_intersection_street_names(int)' /tmp/ccVscFJr.o:/cad2/ece297s/public//m1/tests/m1_func_intersection_toronto_canada_public.cpp:210: more undefined references to `find_intersection_street_names(int)' follow collect2: error: ld returned 1 exit status Build Error: Failed to build unit tests. Compiler returned non-zero exit status 1
Recommended Steps for m1 • Compile • Run ece297exercise 1 • Create empty “stub” implementations of functions in m1.h • Make sure you return something if the function requires it • No more build errors with ece297exercise
Recommended Steps for m1 • Compile • Run ece297exercise 1 • Create “stub” implementations of functions in m1.h • Run ece297exercise 1 • Fail all the tests • Your goal for m1: Fail 0 of the tests
Breaking Maps Up Into Parts Intersection Street Segment
Find Intersection Street Segments • Return a vector of all the street segments connected to an intersection • Our only input is an intnumber • Need to use something that is outside the scope of the function • StreetsDatabaseAPI.h has what we need std::vector<int>find_intersection_street_segments(intintersection_id){ std::vector<int>ss_ids; //... returnss_ids; }
Street Segments in StreetDatabaseAPI.h structInfoStreetSegment{ OSMID wayOSMID;//OSM ID of the source way IntersectionIndexfrom, to;//intersection ID this //segment runs from/to booloneWay;//if true, then can only travel in //from->to direction intcurvePointCount;//number of curve points //between the ends floatspeedLimit;//in km/h StreetIndexstreetID;//index of street this segment //belongs to };
Other Functions in StreetDatabaseAPI.h // access the street segments incident on the intersection (get the count // Nss first, then iterate through segmentNumber=0..Nss-1) intgetIntersectionStreetSegmentCount(IntersectionIndexintersectionIdx); StreetSegmentIndexgetIntersectionStreetSegment(intsegmentNumber, IntersectionIndexintersectionIdx); InfoStreetSegmentgetInfoStreetSegment( StreetSegmentIndexstreetSegmentIdx);
StreetDatabaseAPI: Naming Convention intgetIntersectionStreetSegmentCount(IntersectionIndex id); Lookup Usually O(1) Entity Attribute Often matches 1st argument
Understanding the Data getIntersectionStreetSegment(0, 232) → returns 311 getIntersectionStreetSegment(1, 232) → returns 321 getIntersectionStreetSegment(2, 232) → returns 352 Ordering is irrelevant, but StreetsDatabaseAPI ensures consistent Street Segment ID: 311 Street Segment ID: 321 Street Segment ID: 352 Intersection ID: 232 getInfoStreetSegment({311, 321, 352}) will get a structInfoStreetSegment with data about the street segment getIntersectionStreetSegmentCount(232) → returns 3
Other Functions in StreetDatabaseAPI.h // access the street segments incident on the intersection (get the count // Nss first, then iterate through segmentNumber=0..Nss-1) intgetIntersectionStreetSegmentCount(IntersectionIndexintersectionIdx); StreetSegmentIndexgetIntersectionStreetSegment(intsegmentNumber, IntersectionIndexintersectionIdx); InfoStreetSegmentgetInfoStreetSegment( StreetSegmentIndexstreetSegmentIdx); Be very careful: IntersectionIndex, StreetSegmentIndex, etc. are typedefs to int. You will not get a compiler error if you accidentally swap/compare them! Use descriptive variable names to avoid this.
Implement the Function std::vector<int>find_intersection_street_segments(intintersection_id){ std::vector<int>ss_ids; for(inti=0;i<getIntersectionStreetSegmentCount(intersection_id);++i){ intss_id=getIntersectionStreetSegment(i, intersection_id); ss_ids.push_back(ss_id); } returnss_ids; } Implement Function Here • You will likely need one or more of these function calls: • getIntersectionStreetSegmentCount(…) • getIntersectionStreetSegment(…) • getStreetSegmentInfo(…)
Test the Function std::vector<int>find_intersection_street_segments(intintersection_id){ std::vector<int>ss_ids; for(inti=0;i<getIntersectionStreetSegmentCount(intersection_id);++i){ intss_id=getIntersectionStreetSegment(i, intersection_id); ss_ids.push_back(ss_id); } returnss_ids; } Run intersection tests only: ece297exercise 1 --run_tester ‘*Intersection*’ Passed Functionality Failed Performance
Complexity of our Function std::vector<int>find_intersection_street_segments(intintersection_id){ std::vector<int>ss_ids; for(inti=0;i<getIntersectionStreetSegmentCount(intersection_id);++i){ intss_id=getIntersectionStreetSegment(i, intersection_id); ss_ids.push_back(ss_id); } returnss_ids; } • Assume these are O(1): • getIntersectionStreetSegmentCount(…) • getIntersectionStreetSegment(…) • getStreetSegmentInfo(…) • Complexity? • O(n) • What is n? • Can we reduce the complexity of our function?
Massive hint in m1.cpp boolload_map(std::string map_path){ boolload_successful=false; //Load your map related data structures here returnload_successful; } What data structure can we use for intersection street segments?
What are the Function’s Inputs & Outputs? std::vector<int>find_intersection_street_segments(intintersection_id){ std::vector<int>ss_ids; for(inti=0;i<getIntersectionStreetSegmentCount(intersection_id);++i){ intss_id=getIntersectionStreetSegment(i, intersection_id); ss_ids.push_back(ss_id); } returnss_ids; } • Input • Intersection ID • int • Output • Collection of Street Segment IDs • std::vector<int>
Potential Data Structures • Which data structures can be accessed with an intintersection_id? • std::vector, std::list, std::map, std::unordered_map • What can these data structures contain? • Anything, they are templated • What is the complexity of accessing elements in the data structure? • std::vector – O(1) • std::list – O(n) • std::map – O(log n) • std::unordered_map – O(1) • We would want something less complex than O(n)
Complexity versus Performance std::vector std::unordered_map Accessing an element takes O(1) An access involves: A call to a hash function to get an index A direct memory access The hash function takes time! • Accessing an element takes O(1) • An access involves • a direct memory access (a “load” instruction – ECE243)
When do I need a hash function? • Arrays and vectors are indexed using a number • If we are not indexing with a number, we should use a hash function • The first element starts at 0 • When do I need to not index via a number? • std::string • Custom class • What does unordered_map’s hash function require? • An operator== for the data type being used
Note global variable Loading Data First std::vector<std::vector<int>>intersection_street_segments; boolload_map(std::string map_name){ boolload_successful=loadStreetsDatabaseBIN(map_name); intersection_street_segments.resize(getNumberOfIntersections()); for(intintersection =0; intersection <getNumberOfIntersections(); ++intersection){ for(inti=0;i<getIntersectionStreetSegmentCount(intersection);++i){ intss_id=getIntersectionStreetSegment(i, intersection); intersection_street_segments[intersection].push_back(ss_id); } } returnload_successful; }
Nested Vectors std::vector<std::vector<int>>intersection_street_segments; intersction_street_segments Intersection 1‘s Street Segment IDs std::vector<int> int int int [0] std::vector<int> int int int int int [1] std::vector<int> int int [2] … std::vector<int> int int int int [size() - 1]
Note global variable Loading Data First std::vector<std::vector<int>>intersection_street_segments; boolload_map(std::string map_name){ boolload_successful=loadStreetsDatabaseBIN(map_name); intersection_street_segments.resize(getNumberOfIntersections()); for(intintersection =0; intersection <getNumberOfIntersections(); ++intersection){ for(inti=0;i<getIntersectionStreetSegmentCount(intersection);++i){ intss_id=getIntersectionStreetSegment(i, intersection); intersection_street_segments[intersection].push_back(ss_id); } } returnload_successful; } Notice the global variable. Populate intersection_street_segments here
Loading Data First std::vector<std::vector<int>>intersection_street_segments; boolload_map(std::string map_name){ boolload_successful=loadStreetsDatabaseBIN(map_name); intersection_street_segments.resize(getNumberOfIntersections()); for(intintersection =0; intersection <getNumberOfIntersections(); ++intersection){ for(inti=0;i<getIntersectionStreetSegmentCount(intersection);++i){ intss_id=getIntersectionStreetSegment(i, intersection); intersection_street_segments[intersection].push_back(ss_id); } } returnload_successful; } Notice the global variable. //Create empty //vector for each //intersection //Iterate through all intersections //Iterate through //all segments at //intersection //Memorize/save segment connected to intersection
How does this impact the find function? std::vector<int>find_intersection_street_segments(intintersection_id){ returnintersection_street_segments[intersection_id]; } • Just one line! • Looks up answer from data structure • Index into std::vector of street segments with intersection_id • Much faster: • Single array look-up • O(1)
How does this impact performance? • We moved the complexity to load_map • What is the complexity of the load_map function? • What is the complexity of find_intersection_street_segments? • There is a performance test for load_map too! • You have several seconds to load everything into your data structures • A long time!