Skip to content

Commit

Permalink
Added more cases
Browse files Browse the repository at this point in the history
  • Loading branch information
optiklab committed Jul 15, 2023
1 parent ec67b5b commit 385ffdb
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 21 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@ For BFS and DFS algorithms it should be Zero-Weight Graph. For Dijkstra and A-St
You can keep using graph with weights for BFS and DFS as well, but it will not consider weights for finding a path. Thus, you will clearly see the applicability of each algorithm to certain tasks.

If you want to generate zero-weight graph, then you need to change variable to false:
```bash
bool generateWeights = true;
```

Basically, generate graph looks like this:
If to visualize the graph, it would look like this:
```bash
(0, 0) - (0, 1) - (0, 2) - (0, 3) - (0, 4)
| | | | |
Expand All @@ -58,7 +60,7 @@ Basically, generate graph looks like this:
(4, 0) - (4, 1) - (4, 2) - (4, 3) - (4, 4)
```

where pairs are Row and Column numbers, or you can think of it as X and Y.
where in brackets pairs are Row and Column numbers, or you can think of it as X and Y. Weights generated in both directions, but they are different, meaning that 0->1 has weight 1, while 1->0 has weight 3.

# Graph representation in memory

Expand Down Expand Up @@ -125,7 +127,7 @@ we take the quickiest path in terms of euclidian distance and end up with QUICKI
(4, 4)
```

It might be a bad example to see the difference in speed of those algorithms, so please look at [my other project that implements those algorithms efficiently](https://github.com/optiklab/path-algorithms-on-a-grid-map) and uses more visual approach and much more test data for it.
It's very hard to find a simple enough example of a graph that would show a big difference in Dijkstra and A-Star algorithms. So, please look at [my other project that implements those algorithms efficiently](https://github.com/optiklab/path-algorithms-on-a-grid-map) and uses more visual approach and much more test data for it.

The goal of this project was to show that all four algorithms are very similar.

Expand Down
175 changes: 157 additions & 18 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,6 @@ void createAdjacencyList(vector<GraphNode>& nodes, vector<vector<pair<int, int>>
graph.push_back(connection);
}
}

bool firstLess(std::pair<int, int> lhs, int rhs)
{
return lhs.first < rhs;
Expand Down Expand Up @@ -241,11 +240,12 @@ int calculateCost(Graph& graph, vector<int> path)
return cost;
}

int main(int argc, char** argv)
/// <summary>
/// Creates 25 nodes for a graph of 5 x 5 nodes.
/// </summary>
/// <param name="graph"></param>
void createNodes(Graph& graph)
{
// Generate a graph of 25 (5 x 5 field) nodes, for test purpose.
Graph graph;

graph.Nodes.push_back({ 0, 0 }); // 1 (Index = 0)
graph.Nodes.push_back({ 0, 1 });
graph.Nodes.push_back({ 0, 2 });
Expand All @@ -271,22 +271,22 @@ int main(int argc, char** argv)
graph.Nodes.push_back({ 4, 2 });
graph.Nodes.push_back({ 4, 3 });
graph.Nodes.push_back({ 4, 4 }); // 25 (5x5) (Index = 24)
}

/// <summary>
/// Executes universal path finding algorithm on a generated graph using data structure specified in the method FindPath.
/// </summary>
void executeGeneratedGraph()
{
// Generate a graph of 25 (5 x 5 field) nodes, for test purpose.
Graph graph;
createNodes(graph);

// Now, create a graph representation.
// For BFS and DFS algorithms it should be Zero-Weight Graph. For Dijkstra and A* algorithms it should be Non-Zero-Weight Graph.
bool generateWeights = true;
createAdjacencyList(graph.Nodes, graph.Edges, generateWeights);

//( 0 ) - ( 1 ) - ( 2 ) - ( 3 ) - ( 4 )
// | | | | |
//( 5 ) - ( 6 ) - ( 7 ) - ( 8 ) - ( 9 )
// | | | | |
//( 10 ) - ( 11 ) - ( 12 ) - ( 13 ) - ( 14 )
// | | | | |
//( 15 ) - ( 16 ) - ( 17 ) - ( 18 ) - ( 19 )
// | | | | |
//( 20 ) - ( 21 ) - ( 22 ) - ( 23 ) - ( 24 )

// (0, 0) - (0, 1) - (0, 2) - (0, 3) - (0, 4)
// | | | | |
// (1, 0) - (1, 1) - (1, 2) - (1, 3) - (1, 4)
Expand Down Expand Up @@ -336,8 +336,147 @@ int main(int argc, char** argv)
// (4, 4)

FindAlgorithm algo;
cout << "COST (universal): " << calculateCost(graph, algo.FindPath(graph, 0, 24, graph.Nodes[24].X, graph.Nodes[24].Y)) << endl;
cout << "COST (a-star classic): " << calculateCost(graph, algo.FindPathByClassicAStar(graph, 0, 24, graph.Nodes[24].X, graph.Nodes[24].Y)) << endl;

cout << "COST (universal, Generated Graph): " << calculateCost(graph, algo.FindPath(graph, 0, 24, graph.Nodes[24].X, graph.Nodes[24].Y)) << endl;
cout << "COST (a-star classic, Generated Graph): " << calculateCost(graph, algo.FindPathByClassicAStar(graph, 0, 24, graph.Nodes[24].X, graph.Nodes[24].Y)) << endl;
}

/// <summary>
/// Creates graph with connections and weights that is much better to represent the difference between the algorithms.
/// </summary>
void createCustomGraph(vector<vector<pair<int, int>>>& graph)
{
// (0, 0) -1- (0, 1) -1- (0, 2) -1- (0, 3) -2- (0, 4)
// | | | | |
// 2 1 1 2 2
// | | | | |
// (1, 0) -2- (1, 1) -1- (1, 2) -2- (1, 3) -1- (1, 4)
// | | | | |
// 2 1 1 1 1
// | | | | |
// (2, 0) -1- (2, 1) -1- (2, 2) -1- (2, 3) -2- (2, 4)
// | | | | |
// 2 1 1 1 2
// | | | | |
// (3, 0) -2- (3, 1) -2- (3, 2) -1- (3, 3) -2- (3, 4)
// | | | | |
// 2 1 1 2 2
// | | | | |
// (4, 0) -2- (4, 1) -1- (4, 2) -2- (4, 3) -2- (4, 4)

graph.push_back({ { 1, 1}, { 5, 2} }); // 0
graph.push_back({ { 0, 1}, { 6, 1}, { 2, 1} });
graph.push_back({ { 1, 1}, { 7, 1}, { 3, 1} });
graph.push_back({ { 2, 1}, { 8, 2}, { 4, 2} });
graph.push_back({ { 3, 2}, { 9, 2} });

graph.push_back({ { 0, 2}, { 6, 2}, { 10, 2} }); // 5
graph.push_back({ { 5, 2}, { 1, 1}, { 7, 1}, { 11, 1} });
graph.push_back({ { 2, 2}, { 6, 1}, { 8, 2}, { 12, 1} }); //7
graph.push_back({ { 3, 2}, { 7, 2}, { 9, 1}, { 13, 1} });
graph.push_back({ { 4, 2}, { 8, 1}, { 14, 1} }); // 9

graph.push_back({ { 5, 2}, { 11, 1}, { 15, 2} }); // 10
graph.push_back({ { 10, 1}, { 6, 1}, { 12, 1}, { 16, 1} });
graph.push_back({ { 11, 1}, { 7, 1}, { 13, 1}, { 17, 1} });
graph.push_back({ { 12, 1}, { 8, 1}, { 14, 2}, { 18, 1} });
graph.push_back({ { 13, 2}, { 9, 1}, { 19, 2} }); // 14

graph.push_back({ { 10, 2}, { 16, 2}, { 20, 2} }); // 15
graph.push_back({ { 15, 2}, { 11, 1}, { 17, 2}, { 21, 1} });
graph.push_back({ { 16, 2}, { 12, 1}, { 18, 1}, { 22, 1} });
graph.push_back({ { 17, 1}, { 13, 1}, { 19, 2}, { 23, 2} });
graph.push_back({ { 18, 2}, { 14, 2}, { 24, 2} }); // 19

graph.push_back({ { 15, 2}, { 21, 2} }); // 20
graph.push_back({ { 20, 2}, { 16, 1}, { 22, 1} });
graph.push_back({ { 21, 1}, { 17, 1}, { 23, 2} });
graph.push_back({ { 22, 2}, { 18, 2}, { 24, 2} });
graph.push_back({ { 23, 2}, { 19, 2} }); // 24
}

/// <summary>
/// Executes universal path finding algorithm on a custom graph using data structure specified in the method FindPath.
/// </summary>
void executeCustomGraph()
{
// Generate a graph of 25 (5 x 5 field) nodes, for test purpose.
Graph graph;
createNodes(graph);
createCustomGraph(graph.Edges);

// DFS finds path 24<-23<-22<-21<-20<-15<-10<-5<-0 with COST = 15 (but it doesn't look for COST actually) :
// (0, 0)
// |
// (1, 0)
// |
// (2, 0)
// |
// (3, 0)
// |
// (4, 0) - (4, 1) - (4, 2) - (4, 3) - (4, 4)

// BFS finds other root 24<-19<-14<-9<-8<-7<-6<-1<-0 with the COST=11 (but again, it doesn't look for COST actually) :
// (0, 0) - (0, 1) - (0, 2) - (0, 3) - (0, 4)
// |
// (1, 4)
// |
// (2, 4)
// |
// (3, 4)
// |
// (4, 4)
//
// Dijkstra and A* finds SHORTEST path 24<-19<-18<-13<-12<-7<-6<-1<-0 with COST = 10:
// (0, 0) -1- (0, 1)
// |
// 1
// |
// (1, 1) -1- (1, 2)
// |
// 1
// |
// (2, 2) -1- (2, 3)
// |
// 1
// |
// (3, 3) -1- (3, 4)
// |
// 1
// |
// (4, 4)
//
// Fun enough, if we simply use euclidian logic in selecting the next node for traversal and don't consider weight at all, then
// we take the quickiest path 24<-19<-18<-13<-12<-7<-2<-1<-0 in terms of euclidian distance and end up with QUICKIEST path of COST = 10 (it looks for QUICKIEST, not LOWEST COST):
// (0, 0) -1- (0, 1) -1- (0, 2)
// |
// 1
// |
// (1, 2)
// |
// 1
// |
// (2, 2) -1- (2, 3)
// |
// 1
// |
// (3, 3) -1- (3, 4)
// |
// 1
// |
// (4, 4)

FindAlgorithm algo;
cout << "COST (universal, Custom Graph): " << calculateCost(graph, algo.FindPath(graph, 0, 24, graph.Nodes[24].X, graph.Nodes[24].Y)) << endl;
cout << "COST (a-star classic, Custom Graph): " << calculateCost(graph, algo.FindPathByClassicAStar(graph, 0, 24, graph.Nodes[24].X, graph.Nodes[24].Y)) << endl;
}

int main(int argc, char** argv)
{
cout << "Generated graph: " << endl;
executeGeneratedGraph();

cout << "Custom graph: " << endl;
executeCustomGraph();

return 0;
}

0 comments on commit 385ffdb

Please sign in to comment.