-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
263 changed files
with
122,795 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,11 +25,11 @@ | |
*.la | ||
*.a | ||
*.lib | ||
*.csv | ||
|
||
# Executables | ||
*.exe | ||
*.out | ||
*.app | ||
|
||
./DS_Store | ||
.codegpt | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
cmake_minimum_required(VERSION 3.30) | ||
project(QuickPath) | ||
|
||
set(CMAKE_CXX_STANDARD 23) | ||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") | ||
|
||
add_executable(QuickPath main.cpp | ||
DataIntegrityVerification/DataIntegrity.cpp | ||
src/Graph.cpp | ||
src/PathFinder.cpp | ||
src/RestApi.cpp | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
#include "DataIntegrity.h" | ||
#include <iostream> | ||
#include <fstream> | ||
#include <unordered_map> | ||
#include <unordered_set> | ||
#include <vector> | ||
#include <sstream> | ||
|
||
using namespace std; | ||
|
||
|
||
unordered_map<int, vector<pair<int, int> > > graph; | ||
|
||
|
||
////////////// Add an edge to the graph u landmark_A, v landmark_B, w weight ///////////// | ||
void DataIntegrity::AddEdge(int u, int v, int w){ | ||
graph[u].emplace_back(v, w); | ||
graph[v].emplace_back(u, w); | ||
} | ||
|
||
|
||
////////////////// Load the graph from the CSV file ////////////////// | ||
void DataIntegrity::LoadGraphFromCSV(const std::string& filename){ | ||
ifstream file(filename); // Open the file | ||
if(!file.is_open()){ // Check if the file is open | ||
cout << "Error opening file " << filename << endl; | ||
return; | ||
} | ||
|
||
string line; | ||
|
||
while(getline(file, line)){ | ||
stringstream ss(line); // Convert the line to a stringstream | ||
int node, neighbour, time; // Variables to store the landmark A, landmark B and time/unit, respectively. | ||
char comma; | ||
ss >> node >> comma >> neighbour >> comma >> time; // Read the line | ||
|
||
AddEdge(node, neighbour, time); //call the AddEdge function to add the line to the graph | ||
} | ||
cout << endl; | ||
cout << "CSV file " << filename << " read successfully!" << endl; | ||
ValidateGraphIntegrity(); // call the ValidateGraphIntergrity function to check the integrity of the graph; | ||
file.close(); // Close the file | ||
|
||
} | ||
|
||
|
||
/////////////////// Display the graph //////////////////// | ||
void DataIntegrity::display() const { | ||
for (const auto& [node, neighbors] : graph) { // Iterate through all nodes in the graph | ||
cout << "Landmark " << node << " connects to:" << endl; | ||
for (const auto& [neighbor, weight] : neighbors) { // Iterate through all neighbors of the node | ||
cout << " -> Landmark " << neighbor << " with time " << weight << endl; | ||
} | ||
} | ||
} | ||
|
||
|
||
////////////////////// Check the integrity of the graph by checking if there is any self-loop ////////////////////// | ||
bool DataIntegrity::detectSelfLoop(){ | ||
unordered_set<int> selfLoop; | ||
|
||
for(auto& [node, neighbour] : graph){ // Iterate through all nodes in the graph | ||
for(auto& [neighbor, _] : neighbour){ // Iterate through all neighbors of the node | ||
if(node == neighbor){ // If the node is the same as the neighbor, then there is a self loop | ||
selfLoop.insert(node); // add all the nodes with self loops to selfLoop set | ||
} | ||
} | ||
} | ||
|
||
/* Display the nodes found within the selfLoop set */ | ||
cout << endl; | ||
if (!selfLoop.empty()) { | ||
cout << "Self loop detected at node(s): "; | ||
for (const int node : selfLoop) { | ||
cout << node << " "; | ||
} | ||
cout << "\n" << endl; | ||
return false; | ||
} | ||
|
||
/* If no self loop is found */ | ||
cout << "No self loop detected\n" << endl; | ||
return true; | ||
}; | ||
|
||
|
||
//////////// Check if there is a cycle loop in the graph by iterating through all neighbors of the node ////////////// | ||
bool DataIntegrity::detectCycleLoop(int startNode, unordered_set<int>& visited) { | ||
stack<pair<int, size_t>> nodeStack; // Pair of (node, neighbor_index) | ||
vector<int> currentPath; // Vector to keep track of current path | ||
unordered_map<int, bool> inPath; // Map to keep track of nodes in current path | ||
|
||
// Initialize with start node | ||
nodeStack.push({startNode, 0}); // Push the start node to the stack | ||
currentPath.push_back(startNode); // Add the start node to the current path | ||
inPath[startNode] = true; // Mark the start node as in path | ||
visited.insert(startNode); // Mark the start node as visited | ||
|
||
while (!nodeStack.empty()) { | ||
int currentNode = nodeStack.top().first; // Get the current node from the stack | ||
size_t& index = nodeStack.top().second; // Reference to index to update it in future iterations | ||
|
||
// If we've processed all neighbors of current node | ||
if (index >= graph[currentNode].size()) { | ||
nodeStack.pop(); // Pop the current node from the stack | ||
if (!currentPath.empty()) { | ||
currentPath.pop_back(); // Remove the current node from the path | ||
inPath[currentNode] = false; // Mark the current node as not in path | ||
} | ||
continue; | ||
} | ||
|
||
// Get next neighbor to process | ||
int neighbor = graph[currentNode][index].first; // Using .first since your graph stores pairs of (neighbor, weight) | ||
index++; // Move to next neighbor for future iterations | ||
|
||
// If neighbor is in current path, we found a cycle | ||
if (inPath[neighbor]) { | ||
// Only report cycles of length >= 3 | ||
auto it = find(currentPath.begin(), currentPath.end(), neighbor); // Find the neighbor in the current path | ||
if (distance(it, currentPath.end()) >= 3) { | ||
cout << "\nPath Leader: "; | ||
for (const int n : currentPath) { | ||
cout << n << " -> "; | ||
} | ||
cout << neighbor << endl; | ||
|
||
cout << "CycleLoop Detected: {"; | ||
for (; it != currentPath.end(); ++it) { | ||
cout << *it << " -> "; | ||
} | ||
cout << neighbor << "}" << endl; | ||
return true; | ||
} | ||
continue; | ||
} | ||
|
||
// Skip if already visited (but allow revisiting if it would create a cycle) | ||
if (visited.count(neighbor) && !inPath[neighbor]) { | ||
continue; | ||
} | ||
|
||
// Add neighbor to path and stack | ||
nodeStack.push({neighbor, 0}); | ||
currentPath.push_back(neighbor); // Add the neighbor to the current path | ||
inPath[neighbor] = true; // Mark the neighbor as in path | ||
visited.insert(neighbor); // Mark the neighbor as visited | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/////////////// Check the integrity of the graph by checking if there is any self-loop and cycle loop /////////////// | ||
bool DataIntegrity::ValidateGraphIntegrity() { | ||
unordered_set<int> visited, stack; | ||
vector<int> path; | ||
|
||
bool cycleDetected = true; | ||
|
||
/* Check for self-loops */ | ||
if (!detectSelfLoop()) { | ||
cycleDetected = false; // Invalid graph due to self-loops | ||
} | ||
|
||
/* Check for cyclesLoops */ | ||
for (auto& [node, _] : graph) { // Iterate through all nodes in the graph | ||
if (!visited.count(node) && detectCycleLoop(node, visited)) { | ||
cout << "\nThe graph is not free of loops" << endl; | ||
return false; | ||
} | ||
} | ||
|
||
/* If no self-loops or cyclesLoops are found */ | ||
cout << "\nThe graph is free of loops" << endl; | ||
return cycleDetected; | ||
} | ||
|
||
|
||
////////////// Check the connectivity of the graph ////////////// | ||
bool DataIntegrity::Connectivity() { | ||
unordered_set<int> visited; // Create a set to store visited nodes | ||
DFSConnectivity(graph.begin()->first, visited); | ||
cout << endl; | ||
|
||
if (visited.size() != graph.size()) { | ||
cout << "The graph is not fully connected" << endl; | ||
return false; | ||
} | ||
|
||
cout << "The graph is fully connected" << endl; | ||
return true; | ||
} | ||
|
||
|
||
////////////// Depth First Search to check the connectivity of the graph ////////////// | ||
void DataIntegrity::DFSConnectivity(int node, unordered_set<int>& visited) { | ||
visited.insert(node); // mark the node as visited | ||
stack<int> nodeStack; // Create a stack to store nodes | ||
nodeStack.push(node); // Push the node to the stack | ||
|
||
while (!nodeStack.empty()) { | ||
int currentNode = nodeStack.top(); | ||
nodeStack.pop(); | ||
|
||
for (const auto& [neighbor, _] : graph[currentNode]) { | ||
if (!visited.count(neighbor)) { | ||
visited.insert(neighbor); | ||
nodeStack.push(neighbor); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#ifndef DATAINTEGRITY_H | ||
#define DATAINTEGRITY_H | ||
|
||
#include <unordered_set> | ||
#include <string> | ||
#include <iostream> | ||
|
||
using namespace std; | ||
|
||
|
||
|
||
class DataIntegrity { | ||
public: | ||
bool ValidateGraphIntegrity(); | ||
bool detectCycleLoop(int startNode, unordered_set<int>& visited); | ||
bool detectSelfLoop(); | ||
void LoadGraphFromCSV(const std::string& filename); | ||
void AddEdge(int u, int v, int w); | ||
void display() const; | ||
bool Connectivity(); | ||
void DFSConnectivity(int node, unordered_set<int>& visited); | ||
}; | ||
|
||
|
||
|
||
#endif //DATAINTEGRITY_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
#include <iostream> | ||
#include <sstream> | ||
#include "DataIntegrityVerification/DataIntegrity.h" | ||
#include "src/Graph.hpp" | ||
#include "src/RestApi.hpp" | ||
#include <fstream> | ||
|
||
|
||
int main() { | ||
|
||
/////////// Check the integrity of the graph by checking if there is any self-loop and cycle loop ////////// | ||
DataIntegrity data; | ||
|
||
cout <<endl; | ||
cout << "======================= LOOPS DETECTION ===========================" << endl; | ||
data.LoadGraphFromCSV("../USA-roads.csv"); | ||
|
||
data.Connectivity(); | ||
|
||
/////////////// Quickest Path ///////////////// | ||
Graph graph; | ||
|
||
// First, let's add a counter for coordinates | ||
size_t coordCount = 0; | ||
std::ifstream file("../USA-roads.csv", std::ios::in | std::ios::binary); | ||
if (!file) { | ||
std::cerr << "Failed to open file.\n"; | ||
return 1; | ||
} | ||
|
||
std::string line; | ||
while (std::getline(file, line)) { | ||
std::stringstream ss(line); | ||
std::string landmarkA, landmarkB; | ||
int time; | ||
|
||
std::getline(ss, landmarkA, ','); | ||
std::getline(ss, landmarkB, ','); | ||
ss >> time; | ||
|
||
graph.addEdge(landmarkA, landmarkB, time); | ||
} | ||
|
||
file.close(); | ||
|
||
RestApi api(graph); | ||
api.run(); | ||
return 0; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
#include "Graph.hpp" | ||
#include <iostream> | ||
#include <stdexcept> | ||
#include <queue> | ||
#include <limits> | ||
|
||
//Constructor to initialize the graph object | ||
Graph::Graph() { | ||
forwardEdges.clear(); // Clear the forward edges list | ||
backwardEdges.clear(); //Clear the backward edges list | ||
landmarkDistances.clear(); //Clear the landmark distances list | ||
} | ||
|
||
|
||
//Function to ensure that a node exists in the graph | ||
int Graph::ensureNode(const std::string& landmark) { | ||
if (!nodeIndex.count(landmark)) { //If the landmark is not in the node index | ||
int newIndex = nodeIndex.size(); //Get the new index for the landmark | ||
nodeIndex[landmark] = newIndex; // Map the landmark to the node index | ||
indexToNode.push_back(landmark); // Add the landmark to the index to node list | ||
adjList.emplace_back(); // Add an adjacency list for the new node | ||
forwardEdges.emplace_back(); // Add a forward edge for the new node | ||
backwardEdges.emplace_back(); // Add a backward edge for the new node | ||
return newIndex; | ||
} | ||
return nodeIndex[landmark]; //Return the index of the landmark if the landmark already exists | ||
} | ||
|
||
|
||
//Function to add an edge between two landmarks with a given travel time | ||
void Graph::addEdge(const std::string& landmarkA, const std::string& landmarkB, int time) { | ||
if (time < 0) { | ||
throw std::invalid_argument("Travel time cannot be negative"); | ||
} | ||
int u = ensureNode(landmarkA); //Ensure that the first landmark exists in the graph and get its index | ||
int v = ensureNode(landmarkB); //Ensure that the second landmark exists in the graph and get its index | ||
adjList[u].emplace_back(v, time); //Add an edge between the two landmarks with the given travel time | ||
adjList[v].emplace_back(u, time); | ||
forwardEdges[u].push_back({v, time}); //Add a forward edge between the two landmarks with the given travel time | ||
backwardEdges[v].push_back({u, time}); //Add a backward edge between the two landmarks with the given travel time | ||
|
||
|
||
//Ensure that the forward and backward edges lists are large enough to accommodate the new edge | ||
while (forwardEdges.size() <= std::max(u, v)) { | ||
forwardEdges.emplace_back(); //Add a new forward edge list | ||
backwardEdges.emplace_back(); //Add a new backward edge list | ||
} | ||
} | ||
|
||
//Function to precompute landmark distances for a given list of landmarks | ||
void Graph::precomputeLandmarks(const std::vector<std::string>& landmarks) { | ||
int INF = std::numeric_limits<int>::max(); //Set the maximum value for infinity | ||
for (const std::string& landmark : landmarks) { //For each landmark in the list of landmarks | ||
if (!nodeIndex.count(landmark)) continue; | ||
int start = nodeIndex[landmark]; //Get the index of the landmark | ||
std::vector<int> dist(nodeIndex.size(), INF); //Create a vector to store the distances from the landmark | ||
std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int>>, std::greater<>> pq; //Create a priority queue to store the nodes to visit | ||
dist[start] = 0; //Set the distance from the landmark to itself to 0 | ||
pq.emplace(0, start); //Push the start node to the priority queue | ||
while (!pq.empty()) { //While the priority queue is not empty | ||
auto [d, u] = pq.top(); pq.pop(); //Get the top node from the priority queue | ||
if (d > dist[u]) continue; | ||
for (auto [v, weight] : adjList[u]) { //For each neighbor of the current node | ||
if (dist[u] + weight < dist[v]) { //If the distance to the neighbor through the current node is less than the current distance | ||
dist[v] = dist[u] + weight; //Update the distance to the neighbor | ||
pq.emplace(dist[v], v); //Push the neighbor to the priority queue | ||
} | ||
} | ||
} | ||
landmarkDistances[start] = dist; //Store the distances from the landmark to all other nodes | ||
} | ||
} | ||
|
||
|
Oops, something went wrong.