Skip to content

Commit

Permalink
Merge pull request #22 from ryanelandt/improve_documentation
Browse files Browse the repository at this point in the history
Improved documentation of code and fixed perf bug
  • Loading branch information
ryanelandt authored May 22, 2023
2 parents 674869e + 1d2a67f commit 82a31c8
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 54 deletions.
29 changes: 23 additions & 6 deletions include/flight_planner.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ class IdCity {
bool operator!=(const IdCity& other) const { return !(*this == other); }
bool operator<(const IdCity& other) const { return id_ < other.id_; }

/// Returns the id of the city
int id() const { return id_; }

private:
int id_;
int id_; // Id of the city
};


Expand All @@ -46,6 +47,8 @@ class StateAircraft {
id_city_(id_city), battery_level_hours_(battery_level_hours) {}
StateAircraft() : id_city_(IdCity()), battery_level_hours_(-1.0) {}

/// Calculates the change in battery flying time from this state to another state
/// DeltaBattery = BatteryOther - BatteryThis
double CalcBatteryDelta(const StateAircraft& other) const {
assert(id_city_ == other.id_city_);
return other.battery_level_hours_ - battery_level_hours_;
Expand All @@ -63,12 +66,15 @@ class StateAircraft {
}
}

/// Returns the id of the city
IdCity id_city() const { return id_city_; }

/// Returns the remaining battery flight time in hours
double battery_level_hours() const { return battery_level_hours_; }

private:
IdCity id_city_;
double battery_level_hours_;
IdCity id_city_; // Id of the city
double battery_level_hours_; // Remaining battery flight time in hours
};


Expand Down Expand Up @@ -105,6 +111,9 @@ class FlightPlannerBase : public GraphDirected<StateAircraft> {
}

static constexpr double MinBatteryHours() { return 0.0; }

/// Returns the maximum battery flytime in hours. The maximum flytime is the
/// maximum flight distance 320km divided by the speed of the aircraft.
static constexpr double MaxBatteryHours() { return 320.0 / SpeedKmPerHr(); }
static constexpr double MaxFlightTimeHours() { return MaxBatteryHours() - MinBatteryHours(); }

Expand Down Expand Up @@ -137,7 +146,7 @@ class FlightPlannerBase : public GraphDirected<StateAircraft> {
double CalcChargeRateKmPerHr(const IdCity& id_city) const { return GetAirport(id_city).rate; }

static constexpr double RadEarth() { return 6356.752; } // Radius of Earth in km
static constexpr double SpeedKmPerHr() { return 105.0; } // Speed of aircraft in km/hr
static constexpr double SpeedKmPerHr() { return 105.0; } // Speed of aircraft in km/hr from the problem statement

const std::array<row, 303> airports_; // List of airports copied from the non-constant global in airports.h
};
Expand All @@ -153,6 +162,7 @@ class FlightPlannerExact : public FlightPlannerBase {
}

private:
// Adds edges for this graph construction approach
void AddEdgesFlightsExact();
};

Expand All @@ -170,10 +180,14 @@ class FlightPlannerGrid : public FlightPlannerBase {
AddEdgesCharge();
}

/// Returns the number of battery levels in the grid
int n_levels() const { return n_levels_; }

/// Returns the vector of evenly spaced battery levels
const vector<double>& v_battery_levels() const { return v_battery_levels_; }

private:
// Creates a vector of evenly spaced battery levels between the minimum and maximum battery levels
static vector<double> CreateGridBatteryLevels(int n_levels) {
const double delta_battery = (MaxBatteryHours() - MinBatteryHours()) / (n_levels - 1);

Expand All @@ -186,14 +200,17 @@ class FlightPlannerGrid : public FlightPlannerBase {
return v_battery_levels;
}

// Adds vertices linearly spaced between the minimum and maximum battery levels
void AddVerticesGrid();

// Finds the battery level in the grid that is closest to the given battery level
int FindBatteryLevel(const double battery_level) const;

// Adds approximate edges for this graph construction approach
void AddEdgesDrivingGrid();

const int n_levels_;
const vector<double> v_battery_levels_;
const int n_levels_; // Number of evenly spaced battery levels in the grid
const vector<double> v_battery_levels_; // Vector of evenly spaced battery levels
};

}; // namespace std
3 changes: 3 additions & 0 deletions include/graph_directed.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,10 @@ class GraphDirected {
return make_pair(path, dist[dst]); // Return the shortest path and its cost
}

/// Returns the set of vertices in the graph
const set<VertexType>& vertices() const { return vertices_; }

/// Returns the adjacency list of the graph
const map<VertexType, map<VertexType, double>>& adjacency_list() const { return adjacency_list_; }

private:
Expand Down
97 changes: 51 additions & 46 deletions src/flight_planner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,9 @@ namespace std {
// FlightPlannerBase

pair<vector<StateAircraft>, double> FlightPlannerBase::SolvePath(const char* char_src, const char* char_dst) const {
IdCity id_src = GetIdCity(char_src);
IdCity id_dst = GetIdCity(char_dst);

// Calculate shortest distance from vertex src to every other vertex
StateAircraft src{id_src, MaxBatteryHours()}; // Source city with fully battery
StateAircraft dst{id_dst, MinBatteryHours()}; // Destination city
return CalcMinCostPathDijkstra(src, dst);
StateAircraft src{GetIdCity(char_src), MaxBatteryHours()}; // Source city with fully battery
StateAircraft dst{GetIdCity(char_dst), MinBatteryHours()}; // Destination city
return CalcMinCostPathDijkstra(src, dst); // Solve for the minimum cost path
}

void FlightPlannerBase::AddEdgesCharge() {
Expand All @@ -39,7 +35,7 @@ void FlightPlannerBase::AddEdgesCharge(const IdCity& id_city, const set<StateAir
if (next_it != vertex_states.end()) {
StateAircraft next_vertex_state = *next_it;

double charge_time = CalcChargeTime(vertex_state, next_vertex_state);
const double charge_time = CalcChargeTime(vertex_state, next_vertex_state);

// Represents charging edge
AddDirectedEdge(vertex_state, next_vertex_state, charge_time);
Expand All @@ -60,40 +56,43 @@ IdCity FlightPlannerBase::GetIdCity(const string& name) const {
}

void FlightPlannerBase::PrintPath(const vector<StateAircraft>& v_path) const {
IdCity id_src = v_path[0].id_city();
IdCity id_dst = v_path[v_path.size() - 1].id_city();
IdCity id_src = v_path[0].id_city(); // Id of the first city
IdCity id_dst = v_path[v_path.size() - 1].id_city(); // Id of the last city

cout << endl;
PrintCity(id_src); cout << ", " << endl; // Print first city
PrintChargingCitiesAndTimes(v_path, id_dst); // Print out each city the plane charges at
PrintChargingCitiesAndTimes(v_path, id_dst); // Print out each intermediate city and charging time
PrintCity(id_dst); // Print last city
cout << endl;
}

void FlightPlannerBase::PrintChargingCitiesAndTimes(const vector<StateAircraft>& v_path, const IdCity& id_dst) const {
auto fn_find_last_index_of_city = [this](vector<StateAircraft> v_path, int i) {
int j = i;
while (j < v_path.size() && v_path[i].id_city() == v_path[j].id_city()) {
j++;
// Finds the index where charging stops
auto fn_find_i_stop = [this](const vector<StateAircraft>& v_path, int i_start) {
int i_stop = i_start;
while (v_path[i_start].id_city() == v_path[i_stop].id_city()) { // Is same city
i_stop++;
if (i_stop == v_path.size()) { break; } // Reached the end of the path
}
return j - 1;

return i_stop - 1; // The last index before the city changes
};

// Prints out the change time
auto fn_print_charge_time = [this](vector<StateAircraft> v_path, int i, int j) {
PrintCity(v_path[i]);
double charge_time_hours = CalcChargeTime(v_path[i], v_path[j]);
auto fn_print_charge_time = [this](vector<StateAircraft> v_path, int i_arrive, int i_depart) {
PrintCity(v_path[i_arrive]);
double charge_time_hours = CalcChargeTime(v_path[i_arrive], v_path[i_depart]);
cout << ", " << setprecision(16) << charge_time_hours << "," << endl;
};

// Runs the lambda on each city the plane charges at
int ind_arrive = 1;
int ind_depart = -1;
int i_charge_start = 1;
int i_charge_stop = -1;

while (v_path[ind_arrive].id_city() != id_dst) {
ind_depart = fn_find_last_index_of_city(v_path, ind_arrive);
fn_print_charge_time(v_path, ind_arrive, ind_depart);
ind_arrive = ind_depart + 1;
while (v_path[i_charge_start].id_city() != id_dst) {
i_charge_stop = fn_find_i_stop(v_path, i_charge_start);
fn_print_charge_time(v_path, i_charge_start, i_charge_stop);
i_charge_start = i_charge_stop + 1; // Start at the next city
}
}

Expand All @@ -105,23 +104,25 @@ pair<double, double> FlightPlannerBase::GetLatLonRadians(const IdCity& id_city)
}

double FlightPlannerBase::CalcDistKm(const IdCity& src, const IdCity& dst) const {
double lat1r, lon1r, lat2r, lon2r, u, v;
const auto lat1r_lon1r = GetLatLonRadians(src);
const double lat1r = lat1r_lon1r.first;
const double lon1r = lat1r_lon1r.second;

// Get the latitude and longitude of the source and destination cities in radians
tie(lat1r, lon1r) = GetLatLonRadians(src);
tie(lat2r, lon2r) = GetLatLonRadians(dst);
const auto lat2r_lon2r = GetLatLonRadians(dst);
const double lat2r = lat2r_lon2r.first;
const double lon2r = lat2r_lon2r.second;

// Copilot auto-generated code
u = sin((lat2r - lat1r) / 2);
v = sin((lon2r - lon1r) / 2);
const double u = sin((lat2r - lat1r) / 2);
const double v = sin((lon2r - lon1r) / 2);
return 2.0 * RadEarth() * asin(sqrt(u * u + cos(lat1r) * cos(lat2r) * v * v));
}

double FlightPlannerBase::CalcChargeTime(const StateAircraft& state_lo, const StateAircraft& state_hi) const {
const IdCity& id = state_lo.id_city();
assert(id == state_hi.id_city()); // Charging needs to happen at the same city
assert(id == state_hi.id_city()); // Aircraft can't change cities while charging

const double flight_time_per_charge_hr = CalcChargeRateKmPerHr(id) / SpeedKmPerHr();
const double flight_time_per_charge_hr = CalcChargeRateKmPerHr(id) / SpeedKmPerHr(); // Called R in the readme
return state_lo.CalcBatteryDelta(state_hi) / flight_time_per_charge_hr;
}

Expand All @@ -138,13 +139,16 @@ void FlightPlannerExact::AddEdgesFlightsExact() {

double flight_time = CalcFlightTimeHours(src, dst);
if (flight_time < MaxFlightTimeHours()) {
// Flight that departs with full charge
double max_battery = MaxBatteryHours();
AddDirectedEdge(StateAircraft{src, max_battery}, StateAircraft{dst, max_battery - flight_time}, flight_time);

// Flight that arrives with zero charge
double min_battery = MinBatteryHours();
AddDirectedEdge(StateAircraft{src, flight_time + min_battery}, StateAircraft{dst, min_battery}, flight_time);
{
// Flight that departs with full charge
double max_battery = MaxBatteryHours();
AddDirectedEdge(StateAircraft{src, max_battery}, StateAircraft{dst, max_battery - flight_time}, flight_time);
}
{
// Flight that arrives with zero charge
double min_battery = MinBatteryHours();
AddDirectedEdge(StateAircraft{src, flight_time + min_battery}, StateAircraft{dst, min_battery}, flight_time);
}
}
}
}
Expand All @@ -161,6 +165,7 @@ void FlightPlannerGrid::AddVerticesGrid() {
}
}

// Finds the nearest battery level without going over
int FlightPlannerGrid::FindBatteryLevel(const double battery_level) const {
const vector<double>& v_bat = v_battery_levels();

Expand All @@ -177,14 +182,14 @@ void FlightPlannerGrid::AddEdgesDrivingGrid() {
for (auto vertex_i : vertices()) {
for (int j = 0; j < NumAirports(); j++) {
if (vertex_i.id_city() == IdCity{j}) { continue; }
double flight_time_ij = CalcFlightTimeHours(vertex_i.id_city(), IdCity{j});
double battery_i = vertex_i.battery_level_hours();
double battery_post = battery_i - flight_time_ij;
double battery_min = MinBatteryHours();
const double flight_time_ij = CalcFlightTimeHours(vertex_i.id_city(), IdCity{j});
const double battery_i = vertex_i.battery_level_hours();
const double battery_post = battery_i - flight_time_ij;
const double battery_min = MinBatteryHours();

if (battery_post < battery_min) { continue; }
int ind_lo = FindBatteryLevel(battery_post);
double battery_level_lo = v_battery_levels()[ind_lo];
const int ind_lo = FindBatteryLevel(battery_post);
const double battery_level_lo = v_battery_levels()[ind_lo];
StateAircraft vertex_j_lo{IdCity{j}, battery_level_lo};
AddDirectedEdge(vertex_i, vertex_j_lo, flight_time_ij);
}
Expand Down
4 changes: 2 additions & 2 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ int main(int argc, char** argv) {
return 1;
}

FlightPlannerExact(airports).SolvePathAndPrint(argv[1], argv[2]);
// FlightPlannerGrid(airports, 4).SolvePathAndPrint(argv[1], argv[2]);
FlightPlannerExact(airports).SolvePathAndPrint(argv[1], argv[2]); // Run the exact planner
// FlightPlannerGrid(airports, 4).SolvePathAndPrint(argv[1], argv[2]); // Run the grid planner

return 0;
};

0 comments on commit 82a31c8

Please sign in to comment.