Skip to content

Commit

Permalink
1.0 added to main
Browse files Browse the repository at this point in the history
Merge pull request #22 from algosup/code
  • Loading branch information
AlexisLasselin authored Feb 7, 2025
2 parents 1aa2384 + dd2ee52 commit 3e07f9f
Show file tree
Hide file tree
Showing 263 changed files with 122,795 additions and 3 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
*.la
*.a
*.lib
*.csv

# Executables
*.exe
*.out
*.app

./DS_Store
.codegpt
.DS_Store
12 changes: 12 additions & 0 deletions QuickPath/CMakeLists.txt
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
)
213 changes: 213 additions & 0 deletions QuickPath/DataIntegrityVerification/DataIntegrity.cpp
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);
}
}
}
}
26 changes: 26 additions & 0 deletions QuickPath/DataIntegrityVerification/DataIntegrity.h
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
50 changes: 50 additions & 0 deletions QuickPath/main.cpp
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;
}

74 changes: 74 additions & 0 deletions QuickPath/src/Graph.cpp
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
}
}


Loading

0 comments on commit 3e07f9f

Please sign in to comment.