From 536cf0e9de50ea648ae3c3dd968b89194ee0361f Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Wed, 1 Jan 2025 00:34:56 +0530 Subject: [PATCH 01/14] feature: bellmanFord initial draft --- Headers/0003_Graph/0009_SingleSourceShortestPathBellmanFord.h | 0 .../0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc | 0 SourceCodes/0003_Graph/CMakeLists.txt | 1 + Tests/0003_Graph/0009_SingleSourceShortestPathBellmanFordTest.cc | 0 Tests/0003_Graph/CMakeLists.txt | 1 + 5 files changed, 2 insertions(+) create mode 100644 Headers/0003_Graph/0009_SingleSourceShortestPathBellmanFord.h create mode 100644 SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc create mode 100644 Tests/0003_Graph/0009_SingleSourceShortestPathBellmanFordTest.cc diff --git a/Headers/0003_Graph/0009_SingleSourceShortestPathBellmanFord.h b/Headers/0003_Graph/0009_SingleSourceShortestPathBellmanFord.h new file mode 100644 index 0000000..e69de29 diff --git a/SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc b/SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc new file mode 100644 index 0000000..e69de29 diff --git a/SourceCodes/0003_Graph/CMakeLists.txt b/SourceCodes/0003_Graph/CMakeLists.txt index 0837512..942621c 100644 --- a/SourceCodes/0003_Graph/CMakeLists.txt +++ b/SourceCodes/0003_Graph/CMakeLists.txt @@ -8,6 +8,7 @@ set(0003GRAPH_SOURCES 0006_EulerianPathAndCircuit.cc 0007_MinimumSpanningTreeKruskalAlgorithm.cc 0008_MinimumSpanningTreePrimAlgorithm.cc + 0009_SingleSourceShortestPathBellmanFord.cc ) diff --git a/Tests/0003_Graph/0009_SingleSourceShortestPathBellmanFordTest.cc b/Tests/0003_Graph/0009_SingleSourceShortestPathBellmanFordTest.cc new file mode 100644 index 0000000..e69de29 diff --git a/Tests/0003_Graph/CMakeLists.txt b/Tests/0003_Graph/CMakeLists.txt index b5e4144..3e93f06 100644 --- a/Tests/0003_Graph/CMakeLists.txt +++ b/Tests/0003_Graph/CMakeLists.txt @@ -20,6 +20,7 @@ add_executable( 0006_EulerianPathAndCircuitTest.cc 0007_MinimumSpanningTreeKruskalAlgorithmTest.cc 0008_MinimumSpanningTreePrimAlgorithmTest.cc + 0009_SingleSourceShortestPathBellmanFordTest.cc ) target_link_libraries( From fd397e8ba7644f9904d85eb20389461e806601a6 Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Tue, 7 Jan 2025 23:01:59 +0530 Subject: [PATCH 02/14] feature: bellmanford logic added --- ...0009_SingleSourceShortestPathBellmanFord.h | 44 ++++++++ ...009_SingleSourceShortestPathBellmanFord.cc | 106 ++++++++++++++++++ 2 files changed, 150 insertions(+) diff --git a/Headers/0003_Graph/0009_SingleSourceShortestPathBellmanFord.h b/Headers/0003_Graph/0009_SingleSourceShortestPathBellmanFord.h index e69de29..a100573 100644 --- a/Headers/0003_Graph/0009_SingleSourceShortestPathBellmanFord.h +++ b/Headers/0003_Graph/0009_SingleSourceShortestPathBellmanFord.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +using namespace std; + +namespace SingleSourceShortestPathBellmanFord +{ + class Node + { + public: + int data; + int distance; + Node* parent; + Node(int data); + }; + + class Edge + { + public: + Node* nodeU; + Node* nodeV; + int weight; + Edge(Node* nodeU, Node* nodeV, int weight); + }; + + class Graph + { + private: + map> _adjlist; + map _nodeMap; + vector _edgeList; + Node* MakeOrFindNode(int data); + void InitializeSingleSource(Node* sourceNode); + void Relax(Edge* edge); + void GetShortestPath(Node* node, vector& path); + + + public: + void PushDirectedEdge(int valueU, int valueV, int weight); + bool FindSingleSourceShortestPathBellmanFord(int data); + vector GetShortestPathBellmanFord(Node* node); + }; +} \ No newline at end of file diff --git a/SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc b/SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc index e69de29..d2edee2 100644 --- a/SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc +++ b/SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc @@ -0,0 +1,106 @@ +#include "../Headers/0003_Graph/0009_SingleSourceShortestPathBellmanFord.h" +#include +using namespace std; + +namespace SingleSourceShortestPathBellmanFord +{ + Node::Node(int data) + { + this->data = data; + this->distance = INT_MAX; + this->parent = nullptr; + } + + Edge::Edge(Node* nodeU, Node* nodeV, int weight) + { + this->nodeU = nodeU; + this->nodeV = nodeV; + this->weight = weight; + } + + // Graph Private Member Methods + Node* Graph::MakeOrFindNode(int data) + { + Node* node = nullptr; + if (this->_nodeMap.find(data) == this->_nodeMap.end()) + { + node = new Node(data); + this->_nodeMap[data] = node; + } + else + { + node = this->_nodeMap[data]; + } + return node; + } + + void Graph :: InitializeSingleSource(Node* sourceNode) + { + for (auto& iterator : this->_nodeMap) + { + iterator.second->distance = INT_MAX; + iterator.second->parent = nullptr; + } + sourceNode->distance = 0; + } + + void Graph::Relax(Edge* edge) + { + if (edge->nodeV->distance > (edge->nodeU->distance + edge->weight)) + { + edge->nodeV->distance = edge->nodeU->distance + edge->weight; + edge->nodeV->parent = edge->nodeU; + } + } + + void Graph::GetShortestPath(Node* node, vector& path) + { + path.push_back(node->data); + if (node->parent != nullptr) + { + this->GetShortestPath(node->parent, path); + } + } + + // Graph Public Member Methods + void Graph::PushDirectedEdge(int dataU, int dataV, int weight) + { + Node* nodeU = this->MakeOrFindNode(dataU); + Node* nodeV = this->MakeOrFindNode(dataV); + + this->_adjlist[nodeU].push_back(nodeV); + this->_edgeList.push_back(new Edge(nodeU, nodeV, weight)); + } + + bool Graph::FindSingleSourceShortestPathBellmanFord(int data) + { + Node* source = this->_nodeMap[data]; + + this->InitializeSingleSource(source); + + for (int i = 0; i < this->_nodeMap.size() - 1; i++) + { + for (auto& edge : this->_edgeList) + { + this->Relax(edge); + } + } + + for (auto& edge : this->_edgeList) + { + if (edge->nodeV->distance > (edge->nodeU->distance + edge->weight)) + { + return false; + } + } + return true; + } + + vector Graph::GetShortestPathBellmanFord(Node* node) + { + vector path = {}; + this->GetShortestPath(node, path); + reverse(path.begin(), path.end()); + return path; + } +} \ No newline at end of file From 4ad1a6b3054199247de760cf62c6ed843ebcc90e Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Wed, 8 Jan 2025 00:47:02 +0530 Subject: [PATCH 03/14] fix: get path logic --- Headers/0003_Graph/0009_SingleSourceShortestPathBellmanFord.h | 2 +- .../0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Headers/0003_Graph/0009_SingleSourceShortestPathBellmanFord.h b/Headers/0003_Graph/0009_SingleSourceShortestPathBellmanFord.h index a100573..2c509c9 100644 --- a/Headers/0003_Graph/0009_SingleSourceShortestPathBellmanFord.h +++ b/Headers/0003_Graph/0009_SingleSourceShortestPathBellmanFord.h @@ -39,6 +39,6 @@ namespace SingleSourceShortestPathBellmanFord public: void PushDirectedEdge(int valueU, int valueV, int weight); bool FindSingleSourceShortestPathBellmanFord(int data); - vector GetShortestPathBellmanFord(Node* node); + vector GetShortestPathBellmanFord(int data); }; } \ No newline at end of file diff --git a/SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc b/SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc index d2edee2..71e9f62 100644 --- a/SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc +++ b/SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc @@ -96,9 +96,10 @@ namespace SingleSourceShortestPathBellmanFord return true; } - vector Graph::GetShortestPathBellmanFord(Node* node) + vector Graph::GetShortestPathBellmanFord(int data) { vector path = {}; + Node* node = this->_nodeMap[data]; this->GetShortestPath(node, path); reverse(path.begin(), path.end()); return path; From d13fe39af7a10ecce2b11cc95f2728819209251f Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Wed, 8 Jan 2025 22:35:55 +0530 Subject: [PATCH 04/14] test: bellmanford test added --- ...SingleSourceShortestPathBellmanFordTest.cc | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Tests/0003_Graph/0009_SingleSourceShortestPathBellmanFordTest.cc b/Tests/0003_Graph/0009_SingleSourceShortestPathBellmanFordTest.cc index e69de29..f6e3972 100644 --- a/Tests/0003_Graph/0009_SingleSourceShortestPathBellmanFordTest.cc +++ b/Tests/0003_Graph/0009_SingleSourceShortestPathBellmanFordTest.cc @@ -0,0 +1,30 @@ +#include +#include "../Headers/0003_Graph/0009_SingleSourceShortestPathBellmanFord.h" +#include "../0000_CommonUtilities/UnitTestHelper.h" + +namespace SingleSourceShortestPathBellmanFord +{ + UnitTestHelper unitTestHelper; + + TEST(BellmanFordTest, SimpleTest) + { + Graph graph; + + graph.PushDirectedEdge(0, 1, 6); + graph.PushDirectedEdge(0, 3, 7); + graph.PushDirectedEdge(1, 2, 5); + graph.PushDirectedEdge(1, 3, 8); + graph.PushDirectedEdge(1, 4, -4); + graph.PushDirectedEdge(2, 1, -2); + graph.PushDirectedEdge(3, 2, -3); + graph.PushDirectedEdge(3, 4, 9); + graph.PushDirectedEdge(3, 4, 9); + graph.PushDirectedEdge(4, 2, 7); + graph.PushDirectedEdge(4, 0, 2); + + + string expectedResult = "0 3 2 1 4"; + ASSERT_TRUE(graph.FindSingleSourceShortestPathBellmanFord(0)); + ASSERT_EQ(unitTestHelper.SerializeVectorToString(graph.GetShortestPathBellmanFord(4)), expectedResult); + } +} \ No newline at end of file From d68a35bb353a8eba8a9b60bc29e7845b94461b6c Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Thu, 9 Jan 2025 01:14:25 +0530 Subject: [PATCH 05/14] test: bellmanford more tests added --- ...SingleSourceShortestPathBellmanFordTest.cc | 122 ++++++++++++++---- 1 file changed, 98 insertions(+), 24 deletions(-) diff --git a/Tests/0003_Graph/0009_SingleSourceShortestPathBellmanFordTest.cc b/Tests/0003_Graph/0009_SingleSourceShortestPathBellmanFordTest.cc index f6e3972..f6bc452 100644 --- a/Tests/0003_Graph/0009_SingleSourceShortestPathBellmanFordTest.cc +++ b/Tests/0003_Graph/0009_SingleSourceShortestPathBellmanFordTest.cc @@ -4,27 +4,101 @@ namespace SingleSourceShortestPathBellmanFord { - UnitTestHelper unitTestHelper; - - TEST(BellmanFordTest, SimpleTest) - { - Graph graph; - - graph.PushDirectedEdge(0, 1, 6); - graph.PushDirectedEdge(0, 3, 7); - graph.PushDirectedEdge(1, 2, 5); - graph.PushDirectedEdge(1, 3, 8); - graph.PushDirectedEdge(1, 4, -4); - graph.PushDirectedEdge(2, 1, -2); - graph.PushDirectedEdge(3, 2, -3); - graph.PushDirectedEdge(3, 4, 9); - graph.PushDirectedEdge(3, 4, 9); - graph.PushDirectedEdge(4, 2, 7); - graph.PushDirectedEdge(4, 0, 2); - - - string expectedResult = "0 3 2 1 4"; - ASSERT_TRUE(graph.FindSingleSourceShortestPathBellmanFord(0)); - ASSERT_EQ(unitTestHelper.SerializeVectorToString(graph.GetShortestPathBellmanFord(4)), expectedResult); - } -} \ No newline at end of file + UnitTestHelper unitTestHelper; + + // Test for Simple Graph + TEST(BellmanFordTest, SimpleTest) + { + Graph graph; + + graph.PushDirectedEdge(0, 1, 6); + graph.PushDirectedEdge(0, 3, 7); + graph.PushDirectedEdge(1, 2, 5); + graph.PushDirectedEdge(1, 3, 8); + graph.PushDirectedEdge(1, 4, -4); + graph.PushDirectedEdge(2, 1, -2); + graph.PushDirectedEdge(3, 2, -3); + graph.PushDirectedEdge(3, 4, 9); + graph.PushDirectedEdge(3, 4, 9); + graph.PushDirectedEdge(4, 2, 7); + graph.PushDirectedEdge(4, 0, 2); + + string expectedResult = "0 3 2 1 4"; + ASSERT_TRUE(graph.FindSingleSourceShortestPathBellmanFord(0)); + ASSERT_EQ(unitTestHelper.SerializeVectorToString(graph.GetShortestPathBellmanFord(4)), expectedResult); + } + + // Test for Single Node Graph + TEST(BellmanFordTest, SingleNodeTest) + { + Graph graph; + graph.PushDirectedEdge(0, 0, 0); // Self-loop + + string expectedResult = "0"; + ASSERT_TRUE(graph.FindSingleSourceShortestPathBellmanFord(0)); + ASSERT_EQ(unitTestHelper.SerializeVectorToString(graph.GetShortestPathBellmanFord(0)), expectedResult); + } + + // Test for Negative Weight Cycle + TEST(BellmanFordTest, NegativeWeightCycleTest) + { + Graph graph; + graph.PushDirectedEdge(0, 1, 1); + graph.PushDirectedEdge(1, 2, -1); + graph.PushDirectedEdge(2, 0, -1); // Negative weight cycle + + ASSERT_FALSE(graph.FindSingleSourceShortestPathBellmanFord(0)); + } + + // Test for Multiple Shortest Paths + TEST(BellmanFordTest, MultipleShortestPathsTest) + { + Graph graph; + graph.PushDirectedEdge(0, 1, 5); + graph.PushDirectedEdge(0, 2, 5); + graph.PushDirectedEdge(1, 3, 1); + graph.PushDirectedEdge(2, 3, 1); + + string expectedResult = "0 1 3"; + ASSERT_TRUE(graph.FindSingleSourceShortestPathBellmanFord(0)); + ASSERT_EQ(unitTestHelper.SerializeVectorToString(graph.GetShortestPathBellmanFord(3)), expectedResult); + } + + // Test for All Negative Weights + TEST(BellmanFordTest, AllNegativeWeightsTest) + { + Graph graph; + graph.PushDirectedEdge(0, 1, -5); + graph.PushDirectedEdge(1, 2, -3); + graph.PushDirectedEdge(2, 3, -2); + graph.PushDirectedEdge(3, 4, -1); + + string expectedResult = "0 1 2 3 4"; + ASSERT_TRUE(graph.FindSingleSourceShortestPathBellmanFord(0)); + ASSERT_EQ(unitTestHelper.SerializeVectorToString(graph.GetShortestPathBellmanFord(4)), expectedResult); + } + + // Test for Large Graph + TEST(BellmanFordTest, LargeGraphTest) + { + Graph graph; + for (int i = 0; i < 100; ++i) { + graph.PushDirectedEdge(i, i + 1, 1); + } + + string expectedResult = "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20"; + ASSERT_TRUE(graph.FindSingleSourceShortestPathBellmanFord(0)); + ASSERT_EQ(unitTestHelper.SerializeVectorToString(graph.GetShortestPathBellmanFord(20)), expectedResult); + } + + // Test for Self-Loop Edge + TEST(BellmanFordTest, SelfLoopTest) + { + Graph graph; + graph.PushDirectedEdge(0, 0, 10); // Self-loop with weight 10 + + string expectedResult = "0"; + ASSERT_TRUE(graph.FindSingleSourceShortestPathBellmanFord(0)); + ASSERT_EQ(unitTestHelper.SerializeVectorToString(graph.GetShortestPathBellmanFord(0)), expectedResult); + } +} From 38cec2160d8fdb9c0af63845175c3a6024a6f375 Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Thu, 9 Jan 2025 23:04:00 +0530 Subject: [PATCH 06/14] feature: DAG shortest path initial changes --- .../0010_DirectedAcyclicGraphShortestPath.h | 51 +++++++ .../0010_DirectedAcyclicGraphShortestPath.cc | 124 ++++++++++++++++++ SourceCodes/0003_Graph/CMakeLists.txt | 1 + ...10_DirectedAcyclicGraphShortestPathTest.cc | 0 Tests/0003_Graph/CMakeLists.txt | 1 + 5 files changed, 177 insertions(+) create mode 100644 Headers/0003_Graph/0010_DirectedAcyclicGraphShortestPath.h create mode 100644 SourceCodes/0003_Graph/0010_DirectedAcyclicGraphShortestPath.cc create mode 100644 Tests/0003_Graph/0010_DirectedAcyclicGraphShortestPathTest.cc diff --git a/Headers/0003_Graph/0010_DirectedAcyclicGraphShortestPath.h b/Headers/0003_Graph/0010_DirectedAcyclicGraphShortestPath.h new file mode 100644 index 0000000..37f6610 --- /dev/null +++ b/Headers/0003_Graph/0010_DirectedAcyclicGraphShortestPath.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include +#include +using namespace std; + +namespace DirectedAcyclicGraphShortestPath +{ + enum color {WHITE, GRAY, BLACK}; + + class Node + { + public: + int data; + int color; + int distance; + Node* parent; + Node(int data); + }; + + class Edge + { + public: + Node* nodeU; + Node* nodeV; + int weight; + Edge(Node* nodeU, Node* nodeV, int weight); + }; + + class Graph + { + private: + map> _adjlist; + map _nodeMap; + map> _edgeMap; + list _topologicalSortedNodeList; + Node* MakeOrFindNode(int data); + void DepthFirstSearch(Node* node); + void TopologicalSort(); + void InitializeSingleSource(Node* sourceNode); + void Relax(Edge* edge); + void GetShortestPath(Node* node, vector& path); + + + public: + void PushDirectedEdge(int valueU, int valueV, int weight); + void FindDAGShortestPath(int data); + vector GetDAGShortestPath(int data); + }; +} \ No newline at end of file diff --git a/SourceCodes/0003_Graph/0010_DirectedAcyclicGraphShortestPath.cc b/SourceCodes/0003_Graph/0010_DirectedAcyclicGraphShortestPath.cc new file mode 100644 index 0000000..1fb3621 --- /dev/null +++ b/SourceCodes/0003_Graph/0010_DirectedAcyclicGraphShortestPath.cc @@ -0,0 +1,124 @@ +#include "../Headers/0003_Graph/0010_DirectedAcyclicGraphShortestPath.h" +#include +using namespace std; + +namespace DirectedAcyclicGraphShortestPath +{ + Node::Node(int data) + { + this->data = data; + this->color = WHITE; + this->distance = INT_MAX; + this->parent = nullptr; + } + + Edge::Edge(Node* nodeU, Node* nodeV, int weight) + { + this->nodeU = nodeU; + this->nodeV = nodeV; + this->weight = weight; + } + + // Graph Private Member Methods + Node* Graph::MakeOrFindNode(int data) + { + Node* node = nullptr; + if (this->_nodeMap.find(data) == this->_nodeMap.end()) + { + node = new Node(data); + this->_nodeMap[data] = node; + } + else + { + node = this->_nodeMap[data]; + } + return node; + } + + void Graph::DepthFirstSearch(Node* nodeU) + { + nodeU->color = GRAY; + for (auto nodeV : this->_adjlist[nodeU]) + { + if (nodeV->color == WHITE) + { + nodeV->parent = nodeU; + this->DepthFirstSearch(nodeV); + } + } + nodeU->color = BLACK; + this->_topologicalSortedNodeList.push_front(nodeU); + } + + void Graph::TopologicalSort() + { + for (auto& iterator : this->_nodeMap) + { + if (iterator.second->color == WHITE) + { + this->DepthFirstSearch(iterator.second); + } + } + } + + void Graph::InitializeSingleSource(Node* sourceNode) + { + for (auto& iterator : this->_nodeMap) + { + iterator.second->distance = INT_MAX; + iterator.second->parent = nullptr; + } + sourceNode->distance = 0; + } + + void Graph::Relax(Edge* edge) + { + if (edge->nodeV->distance > (edge->nodeU->distance + edge->weight)) + { + edge->nodeV->distance = edge->nodeU->distance + edge->weight; + edge->nodeV->parent = edge->nodeU; + } + } + + void Graph::GetShortestPath(Node* node, vector& path) + { + path.push_back(node->data); + if (node->parent != nullptr) + { + this->GetShortestPath(node->parent, path); + } + } + + // Graph Public Member Methods + void Graph::PushDirectedEdge(int dataU, int dataV, int weight) + { + Node* nodeU = this->MakeOrFindNode(dataU); + Node* nodeV = this->MakeOrFindNode(dataV); + + this->_adjlist[nodeU].push_back(nodeV); + this->_edgeMap[nodeU].push_back(new Edge(nodeU, nodeV, weight)); + } + + void Graph::FindDAGShortestPath(int data) + { + this->TopologicalSort(); + Node* source = this->_nodeMap[data]; + this->InitializeSingleSource(source); + for (auto& node : this->_topologicalSortedNodeList) + { + for (auto& edge : this->_edgeMap[node]) + { + this->Relax(edge); + } + } + } + + vector Graph::GetDAGShortestPath(int data) + { + vector path = {}; + Node* node = this->_nodeMap[data]; + this->GetShortestPath(node, path); + reverse(path.begin(), path.end()); + return path; + } +} \ No newline at end of file diff --git a/SourceCodes/0003_Graph/CMakeLists.txt b/SourceCodes/0003_Graph/CMakeLists.txt index 942621c..5ddfee0 100644 --- a/SourceCodes/0003_Graph/CMakeLists.txt +++ b/SourceCodes/0003_Graph/CMakeLists.txt @@ -9,6 +9,7 @@ set(0003GRAPH_SOURCES 0007_MinimumSpanningTreeKruskalAlgorithm.cc 0008_MinimumSpanningTreePrimAlgorithm.cc 0009_SingleSourceShortestPathBellmanFord.cc + 0010_DirectedAcyclicGraphShortestPath.cc ) diff --git a/Tests/0003_Graph/0010_DirectedAcyclicGraphShortestPathTest.cc b/Tests/0003_Graph/0010_DirectedAcyclicGraphShortestPathTest.cc new file mode 100644 index 0000000..e69de29 diff --git a/Tests/0003_Graph/CMakeLists.txt b/Tests/0003_Graph/CMakeLists.txt index 3e93f06..66a6d5b 100644 --- a/Tests/0003_Graph/CMakeLists.txt +++ b/Tests/0003_Graph/CMakeLists.txt @@ -21,6 +21,7 @@ add_executable( 0007_MinimumSpanningTreeKruskalAlgorithmTest.cc 0008_MinimumSpanningTreePrimAlgorithmTest.cc 0009_SingleSourceShortestPathBellmanFordTest.cc + 0010_DirectedAcyclicGraphShortestPathTest.cc ) target_link_libraries( From 1b3a3d7935fb9931f1170fab58cc6b15da658501 Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Fri, 10 Jan 2025 02:05:21 +0530 Subject: [PATCH 07/14] test: DAG shortest path test added --- .../0003_Graph/0003_TopologicalSort.cc | 2 +- ...009_SingleSourceShortestPathBellmanFord.cc | 2 +- .../0010_DirectedAcyclicGraphShortestPath.cc | 5 ++-- ...10_DirectedAcyclicGraphShortestPathTest.cc | 29 +++++++++++++++++++ 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/SourceCodes/0003_Graph/0003_TopologicalSort.cc b/SourceCodes/0003_Graph/0003_TopologicalSort.cc index 18dd52a..526456c 100644 --- a/SourceCodes/0003_Graph/0003_TopologicalSort.cc +++ b/SourceCodes/0003_Graph/0003_TopologicalSort.cc @@ -36,7 +36,7 @@ namespace TopologicalSort this->time++; nodeU->discoveryTime = this->time; nodeU->color = GRAY; - for (auto nodeV : this->_adjlist[nodeU]) + for (auto& nodeV : this->_adjlist[nodeU]) { if (nodeV->color == WHITE) { diff --git a/SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc b/SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc index 71e9f62..ba1e747 100644 --- a/SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc +++ b/SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc @@ -46,7 +46,7 @@ namespace SingleSourceShortestPathBellmanFord void Graph::Relax(Edge* edge) { - if (edge->nodeV->distance > (edge->nodeU->distance + edge->weight)) + if (edge->nodeU->distance != INT_MAX && (edge->nodeV->distance > (edge->nodeU->distance + edge->weight))) { edge->nodeV->distance = edge->nodeU->distance + edge->weight; edge->nodeV->parent = edge->nodeU; diff --git a/SourceCodes/0003_Graph/0010_DirectedAcyclicGraphShortestPath.cc b/SourceCodes/0003_Graph/0010_DirectedAcyclicGraphShortestPath.cc index 1fb3621..62cf4bc 100644 --- a/SourceCodes/0003_Graph/0010_DirectedAcyclicGraphShortestPath.cc +++ b/SourceCodes/0003_Graph/0010_DirectedAcyclicGraphShortestPath.cc @@ -38,11 +38,10 @@ namespace DirectedAcyclicGraphShortestPath void Graph::DepthFirstSearch(Node* nodeU) { nodeU->color = GRAY; - for (auto nodeV : this->_adjlist[nodeU]) + for (auto& nodeV : this->_adjlist[nodeU]) { if (nodeV->color == WHITE) { - nodeV->parent = nodeU; this->DepthFirstSearch(nodeV); } } @@ -73,7 +72,7 @@ namespace DirectedAcyclicGraphShortestPath void Graph::Relax(Edge* edge) { - if (edge->nodeV->distance > (edge->nodeU->distance + edge->weight)) + if (edge->nodeU->distance != INT_MAX && (edge->nodeV->distance > (edge->nodeU->distance + edge->weight))) { edge->nodeV->distance = edge->nodeU->distance + edge->weight; edge->nodeV->parent = edge->nodeU; diff --git a/Tests/0003_Graph/0010_DirectedAcyclicGraphShortestPathTest.cc b/Tests/0003_Graph/0010_DirectedAcyclicGraphShortestPathTest.cc index e69de29..3a59445 100644 --- a/Tests/0003_Graph/0010_DirectedAcyclicGraphShortestPathTest.cc +++ b/Tests/0003_Graph/0010_DirectedAcyclicGraphShortestPathTest.cc @@ -0,0 +1,29 @@ +#include +#include "../Headers/0003_Graph/0010_DirectedAcyclicGraphShortestPath.h" +#include "../0000_CommonUtilities/UnitTestHelper.h" + +namespace DirectedAcyclicGraphShortestPath +{ + UnitTestHelper unitTestHelper; + + // Test for Simple Graph + TEST(DAGTest, SimpleGraph) + { + Graph graph; + + graph.PushDirectedEdge(0, 1, 5); + graph.PushDirectedEdge(0, 2, 3); + graph.PushDirectedEdge(1, 2, 2); + graph.PushDirectedEdge(1, 3, 6); + graph.PushDirectedEdge(2, 3, 7); + graph.PushDirectedEdge(2, 4, 4); + graph.PushDirectedEdge(2, 5, 2); + graph.PushDirectedEdge(3, 4, -1); + graph.PushDirectedEdge(3, 5, 1); + graph.PushDirectedEdge(4, 5, -2); + + graph.FindDAGShortestPath(1); + string expectedPath = "1 3 4 5"; + ASSERT_EQ(unitTestHelper.SerializeVectorToString(graph.GetDAGShortestPath(5)), expectedPath); + } +} \ No newline at end of file From 70be7890f32147f3f32ca3685d905cdfd30e2b94 Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Fri, 10 Jan 2025 02:10:19 +0530 Subject: [PATCH 08/14] fix: include file added --- .../0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc | 1 + SourceCodes/0003_Graph/0010_DirectedAcyclicGraphShortestPath.cc | 1 + 2 files changed, 2 insertions(+) diff --git a/SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc b/SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc index ba1e747..5d2decf 100644 --- a/SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc +++ b/SourceCodes/0003_Graph/0009_SingleSourceShortestPathBellmanFord.cc @@ -1,5 +1,6 @@ #include "../Headers/0003_Graph/0009_SingleSourceShortestPathBellmanFord.h" #include +#include using namespace std; namespace SingleSourceShortestPathBellmanFord diff --git a/SourceCodes/0003_Graph/0010_DirectedAcyclicGraphShortestPath.cc b/SourceCodes/0003_Graph/0010_DirectedAcyclicGraphShortestPath.cc index 62cf4bc..da683fb 100644 --- a/SourceCodes/0003_Graph/0010_DirectedAcyclicGraphShortestPath.cc +++ b/SourceCodes/0003_Graph/0010_DirectedAcyclicGraphShortestPath.cc @@ -1,5 +1,6 @@ #include "../Headers/0003_Graph/0010_DirectedAcyclicGraphShortestPath.h" #include +#include using namespace std; namespace DirectedAcyclicGraphShortestPath From 449ab2aab199a28c2e626c6fbeee3b8099c0cc25 Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Mon, 13 Jan 2025 01:16:04 +0530 Subject: [PATCH 09/14] feature-test: dijkstra logic, test added --- .../0011_SingleSourceShortestPathDijkstra.h | 55 +++++++++ .../0011_SingleSourceShortestPathDijkstra.cc | 112 ++++++++++++++++++ SourceCodes/0003_Graph/CMakeLists.txt | 1 + ...11_SingleSourceShortestPathDijkstraTest.cc | 31 +++++ Tests/0003_Graph/CMakeLists.txt | 1 + 5 files changed, 200 insertions(+) create mode 100644 Headers/0003_Graph/0011_SingleSourceShortestPathDijkstra.h create mode 100644 SourceCodes/0003_Graph/0011_SingleSourceShortestPathDijkstra.cc create mode 100644 Tests/0003_Graph/0011_SingleSourceShortestPathDijkstraTest.cc diff --git a/Headers/0003_Graph/0011_SingleSourceShortestPathDijkstra.h b/Headers/0003_Graph/0011_SingleSourceShortestPathDijkstra.h new file mode 100644 index 0000000..c2eccfe --- /dev/null +++ b/Headers/0003_Graph/0011_SingleSourceShortestPathDijkstra.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include +using namespace std; + +namespace SingleSourceShortestPathDijkstra +{ + class Node + { + public: + int data; + int distance; + Node* parent; + Node(int data); + }; + + class Edge + { + public: + Node* nodeU; + Node* nodeV; + int weight; + Edge(Node* nodeU, Node* nodeV, int weight); + }; + + class CompareNodeDistance + { + public: + bool operator()(const Node* nodeU, const Node* nodeV) const + { + return nodeU->distance < nodeV->distance; + } + }; + + class Graph + { + private: + map> _adjlist; + map _nodeMap; + map> _edgeMap; + multiset _operationalSet; + Node* MakeOrFindNode(int data); + void InitializeSingleSource(Node* sourceNode); + void Relax(Edge* edge); + void Dijkstra(Node* source); + void GetShortestPath(Node* node, vector& path); + + public: + void PushDirectedEdge(int valueU, int valueV, int weight); + void FindShortestPathDijkstra(int data); + vector GetDijkstraShortestPath(int data); + }; +} \ No newline at end of file diff --git a/SourceCodes/0003_Graph/0011_SingleSourceShortestPathDijkstra.cc b/SourceCodes/0003_Graph/0011_SingleSourceShortestPathDijkstra.cc new file mode 100644 index 0000000..ac5d068 --- /dev/null +++ b/SourceCodes/0003_Graph/0011_SingleSourceShortestPathDijkstra.cc @@ -0,0 +1,112 @@ +#include "../Headers/0003_Graph/0011_SingleSourceShortestPathDijkstra.h" +#include +using namespace std; + +namespace SingleSourceShortestPathDijkstra +{ + Node::Node(int data) + { + this->data = data; + this->distance = INT_MAX; + this->parent = nullptr; + } + + Edge::Edge(Node* nodeU, Node* nodeV, int weight) + { + this->nodeU = nodeU; + this->nodeV = nodeV; + this->weight = weight; + } + + // Graph Private Member Methods + Node* Graph::MakeOrFindNode(int data) + { + Node* node = nullptr; + if (this->_nodeMap.find(data) == this->_nodeMap.end()) + { + node = new Node(data); + this->_nodeMap[data] = node; + } + else + { + node = this->_nodeMap[data]; + } + return node; + } + + void Graph::InitializeSingleSource(Node* sourceNode) + { + for (auto& iterator : this->_nodeMap) + { + iterator.second->distance = INT_MAX; + iterator.second->parent = nullptr; + } + sourceNode->distance = 0; + } + + void Graph::Relax(Edge* edge) + { + if (edge->nodeU->distance != INT_MAX && (edge->nodeV->distance > (edge->nodeU->distance + edge->weight))) + { + this->_operationalSet.erase(edge->nodeV); + edge->nodeV->distance = edge->nodeU->distance + edge->weight; + edge->nodeV->parent = edge->nodeU; + this->_operationalSet.insert(edge->nodeV); + } + } + + void Graph::Dijkstra(Node* source) + { + this->InitializeSingleSource(source); + + for (auto& node : this->_nodeMap) + { + this->_operationalSet.insert(node.second); + } + + while (!this->_operationalSet.empty()) + { + Node* nodeU = *(this->_operationalSet.begin()); + this->_operationalSet.erase(nodeU); + + for (auto& edge : this->_edgeMap[nodeU]) + { + this->Relax(edge); + } + } + } + + void Graph::GetShortestPath(Node* node, vector& path) + { + path.push_back(node->data); + if (node->parent != nullptr) + { + this->GetShortestPath(node->parent, path); + } + } + + // Graph Public Member Methods + void Graph::PushDirectedEdge(int dataU, int dataV, int weight) + { + Node* nodeU = this->MakeOrFindNode(dataU); + Node* nodeV = this->MakeOrFindNode(dataV); + + this->_adjlist[nodeU].push_back(nodeV); + this->_edgeMap[nodeU].push_back(new Edge(nodeU, nodeV, weight)); + } + + void Graph::FindShortestPathDijkstra(int data) + { + Node* source = this->_nodeMap[data]; + this->Dijkstra(source); + } + + vector Graph::GetDijkstraShortestPath(int data) + { + vector path = {}; + Node* node = this->_nodeMap[data]; + this->GetShortestPath(node, path); + reverse(path.begin(), path.end()); + return path; + } +} \ No newline at end of file diff --git a/SourceCodes/0003_Graph/CMakeLists.txt b/SourceCodes/0003_Graph/CMakeLists.txt index 5ddfee0..eb010e7 100644 --- a/SourceCodes/0003_Graph/CMakeLists.txt +++ b/SourceCodes/0003_Graph/CMakeLists.txt @@ -10,6 +10,7 @@ set(0003GRAPH_SOURCES 0008_MinimumSpanningTreePrimAlgorithm.cc 0009_SingleSourceShortestPathBellmanFord.cc 0010_DirectedAcyclicGraphShortestPath.cc + 0011_SingleSourceShortestPathDijkstra.cc ) diff --git a/Tests/0003_Graph/0011_SingleSourceShortestPathDijkstraTest.cc b/Tests/0003_Graph/0011_SingleSourceShortestPathDijkstraTest.cc new file mode 100644 index 0000000..4f0be15 --- /dev/null +++ b/Tests/0003_Graph/0011_SingleSourceShortestPathDijkstraTest.cc @@ -0,0 +1,31 @@ +#include +#include "../Headers/0003_Graph/0011_SingleSourceShortestPathDijkstra.h" +#include "../0000_CommonUtilities/UnitTestHelper.h" + +namespace SingleSourceShortestPathDijkstra +{ + UnitTestHelper unitTestHelper; + + // Test for Simple Graph + TEST(DijkstraTest, SimpleGraph) + { + Graph graph; + + graph.PushDirectedEdge(0, 1, 10); + graph.PushDirectedEdge(0, 3, 5); + graph.PushDirectedEdge(1, 2, 1); + graph.PushDirectedEdge(1, 3, 2); + graph.PushDirectedEdge(2, 4, 4); + graph.PushDirectedEdge(3, 1, 3); + graph.PushDirectedEdge(3, 2, 9); + graph.PushDirectedEdge(3, 4, 2); + graph.PushDirectedEdge(4, 2, 6); + graph.PushDirectedEdge(4, 0, 7); + + graph.FindShortestPathDijkstra(0); + + string expectedPath = "0 3 1 2"; + + ASSERT_EQ(unitTestHelper.SerializeVectorToString(graph.GetDijkstraShortestPath(2)), expectedPath); + } +} \ No newline at end of file diff --git a/Tests/0003_Graph/CMakeLists.txt b/Tests/0003_Graph/CMakeLists.txt index 66a6d5b..42d15cb 100644 --- a/Tests/0003_Graph/CMakeLists.txt +++ b/Tests/0003_Graph/CMakeLists.txt @@ -22,6 +22,7 @@ add_executable( 0008_MinimumSpanningTreePrimAlgorithmTest.cc 0009_SingleSourceShortestPathBellmanFordTest.cc 0010_DirectedAcyclicGraphShortestPathTest.cc + 0011_SingleSourceShortestPathDijkstraTest.cc ) target_link_libraries( From e91d2f50f5bbed4aab5b3d598a1dd1a485f3390b Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Mon, 13 Jan 2025 01:19:38 +0530 Subject: [PATCH 10/14] fix: algorithm include file added --- SourceCodes/0003_Graph/0011_SingleSourceShortestPathDijkstra.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/SourceCodes/0003_Graph/0011_SingleSourceShortestPathDijkstra.cc b/SourceCodes/0003_Graph/0011_SingleSourceShortestPathDijkstra.cc index ac5d068..138899f 100644 --- a/SourceCodes/0003_Graph/0011_SingleSourceShortestPathDijkstra.cc +++ b/SourceCodes/0003_Graph/0011_SingleSourceShortestPathDijkstra.cc @@ -1,5 +1,6 @@ #include "../Headers/0003_Graph/0011_SingleSourceShortestPathDijkstra.h" #include +#include using namespace std; namespace SingleSourceShortestPathDijkstra From a88931d06e464ddef6b0c32b48e430649001c3e4 Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Tue, 14 Jan 2025 00:47:16 +0530 Subject: [PATCH 11/14] feature: diff constraints initial changes --- .../0012_DifferenceConstraintsShortestPaths.h | 43 +++++++++++++ ...0012_DifferenceConstraintsShortestPaths.cc | 62 +++++++++++++++++++ SourceCodes/0003_Graph/CMakeLists.txt | 1 + ..._DifferenceConstraintsShortestPathsTest.cc | 0 Tests/0003_Graph/CMakeLists.txt | 1 + 5 files changed, 107 insertions(+) create mode 100644 Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h create mode 100644 SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc create mode 100644 Tests/0003_Graph/0012_DifferenceConstraintsShortestPathsTest.cc diff --git a/Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h b/Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h new file mode 100644 index 0000000..bedce6c --- /dev/null +++ b/Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +using namespace std; + +namespace DifferenceConstraintsShortestPaths +{ + class Node + { + public: + int data; + int distance; + Node(int data); + }; + + class Edge + { + public: + Node* nodeU; + Node* nodeV; + int weight; + Edge(Node* nodeU, Node* nodeV, int weight); + }; + + class Graph + { + private: + map> _adjlist; + map _nodeMap; + vector _edgeList; + Node* MakeOrFindNode(int data); + void InitializeSingleSource(Node* sourceNode); + void Relax(Edge* edge); + void GetShortestPath(Node* node, vector& path); + + + public: + void PushDirectedEdge(int valueU, int valueV, int weight); + bool FindSingleSourceShortestPathBellmanFord(int data); + vector GetShortestPathBellmanFord(int data); + }; +} \ No newline at end of file diff --git a/SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc b/SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc new file mode 100644 index 0000000..dba38f7 --- /dev/null +++ b/SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc @@ -0,0 +1,62 @@ +#include"../Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h" +#include +using namespace std; + +namespace DifferenceConstraintsShortestPaths +{ + Node::Node(int data) + { + this->data = data; + this->distance = INT_MAX; + } + + Edge::Edge(Node* nodeU, Node* nodeV, int weight) + { + this->nodeU = nodeU; + this->nodeV = nodeV; + this->weight = weight; + } + + // Graph Private Member Methods + Node* Graph::MakeOrFindNode(int data) + { + Node* node = nullptr; + if (this->_nodeMap.find(data) == this->_nodeMap.end()) + { + node = new Node(data); + this->_nodeMap[data] = node; + } + else + { + node = this->_nodeMap[data]; + } + return node; + } + + void Graph::InitializeSingleSource(Node* sourceNode) + { + for (auto& iterator : this->_nodeMap) + { + iterator.second->distance = INT_MAX; + } + sourceNode->distance = 0; + } + + void Graph::Relax(Edge* edge) + { + if (edge->nodeU->distance != INT_MAX && (edge->nodeV->distance > (edge->nodeU->distance + edge->weight))) + { + edge->nodeV->distance = edge->nodeU->distance + edge->weight; + } + } + + // Graph Public Member Methods + void Graph::PushDirectedEdge(int dataU, int dataV, int weight) + { + Node* nodeU = this->MakeOrFindNode(dataU); + Node* nodeV = this->MakeOrFindNode(dataV); + + this->_adjlist[nodeU].push_back(nodeV); + this->_edgeList.push_back(new Edge(nodeU, nodeV, weight)); + } +} \ No newline at end of file diff --git a/SourceCodes/0003_Graph/CMakeLists.txt b/SourceCodes/0003_Graph/CMakeLists.txt index eb010e7..d2171df 100644 --- a/SourceCodes/0003_Graph/CMakeLists.txt +++ b/SourceCodes/0003_Graph/CMakeLists.txt @@ -11,6 +11,7 @@ set(0003GRAPH_SOURCES 0009_SingleSourceShortestPathBellmanFord.cc 0010_DirectedAcyclicGraphShortestPath.cc 0011_SingleSourceShortestPathDijkstra.cc + 0012_DifferenceConstraintsShortestPaths.cc ) diff --git a/Tests/0003_Graph/0012_DifferenceConstraintsShortestPathsTest.cc b/Tests/0003_Graph/0012_DifferenceConstraintsShortestPathsTest.cc new file mode 100644 index 0000000..e69de29 diff --git a/Tests/0003_Graph/CMakeLists.txt b/Tests/0003_Graph/CMakeLists.txt index 42d15cb..1d024f1 100644 --- a/Tests/0003_Graph/CMakeLists.txt +++ b/Tests/0003_Graph/CMakeLists.txt @@ -23,6 +23,7 @@ add_executable( 0009_SingleSourceShortestPathBellmanFordTest.cc 0010_DirectedAcyclicGraphShortestPathTest.cc 0011_SingleSourceShortestPathDijkstraTest.cc + 0012_DifferenceConstraintsShortestPathsTest.cc ) target_link_libraries( From 6af7c03d7bc0a57fcef24fea6add0183fdd81d98 Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Tue, 14 Jan 2025 01:12:25 +0530 Subject: [PATCH 12/14] fix: node class fix for diff constraint --- .../0012_DifferenceConstraintsShortestPaths.h | 17 ++++---- ...0012_DifferenceConstraintsShortestPaths.cc | 40 +++++++++++++++---- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h b/Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h index bedce6c..f34d1e1 100644 --- a/Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h +++ b/Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include using namespace std; @@ -9,9 +10,9 @@ namespace DifferenceConstraintsShortestPaths class Node { public: - int data; + string data; int distance; - Node(int data); + Node(string data); }; class Edge @@ -26,18 +27,18 @@ namespace DifferenceConstraintsShortestPaths class Graph { private: + Node* startingNode; map> _adjlist; - map _nodeMap; + map _nodeMap; vector _edgeList; - Node* MakeOrFindNode(int data); + Node* MakeOrFindNode(string data); + void PushDirectedEdge(string valueU, string valueV, int weight); void InitializeSingleSource(Node* sourceNode); void Relax(Edge* edge); - void GetShortestPath(Node* node, vector& path); public: - void PushDirectedEdge(int valueU, int valueV, int weight); - bool FindSingleSourceShortestPathBellmanFord(int data); - vector GetShortestPathBellmanFord(int data); + void PushAllDirectedEdges(vector> vectorA, vector vectorX, vector vectorB); + }; } \ No newline at end of file diff --git a/SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc b/SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc index dba38f7..2e48f2b 100644 --- a/SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc +++ b/SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc @@ -4,7 +4,7 @@ using namespace std; namespace DifferenceConstraintsShortestPaths { - Node::Node(int data) + Node::Node(string data) { this->data = data; this->distance = INT_MAX; @@ -18,7 +18,7 @@ namespace DifferenceConstraintsShortestPaths } // Graph Private Member Methods - Node* Graph::MakeOrFindNode(int data) + Node* Graph::MakeOrFindNode(string data) { Node* node = nullptr; if (this->_nodeMap.find(data) == this->_nodeMap.end()) @@ -33,6 +33,15 @@ namespace DifferenceConstraintsShortestPaths return node; } + void Graph::PushDirectedEdge(string dataU, string dataV, int weight) + { + Node* nodeU = this->MakeOrFindNode(dataU); + Node* nodeV = this->MakeOrFindNode(dataV); + + this->_adjlist[nodeU].push_back(nodeV); + this->_edgeList.push_back(new Edge(nodeU, nodeV, weight)); + } + void Graph::InitializeSingleSource(Node* sourceNode) { for (auto& iterator : this->_nodeMap) @@ -51,12 +60,27 @@ namespace DifferenceConstraintsShortestPaths } // Graph Public Member Methods - void Graph::PushDirectedEdge(int dataU, int dataV, int weight) + void Graph::PushAllDirectedEdges(vector> vectorA, vector vectorX, vector vectorB) { - Node* nodeU = this->MakeOrFindNode(dataU); - Node* nodeV = this->MakeOrFindNode(dataV); - - this->_adjlist[nodeU].push_back(nodeV); - this->_edgeList.push_back(new Edge(nodeU, nodeV, weight)); + // Creating the Graph + string valueU = ""; + string valueV = ""; + int weight = 0; + for (int i = 0; i < vectorA.size(); i++) + { + for (int j = 0; j < vectorX.size(); j++) + { + if (vectorA[i][j] == 1) + { + valueV= vectorX[j]; + } + if (vectorA[i][j] == -1) + { + valueU = vectorX[j]; + } + } + weight = vectorB[i]; + this->PushDirectedEdge(valueU, valueV, weight); + } } } \ No newline at end of file From d844a8cf798582f4a8ea69a36931fa52529e5f43 Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Tue, 14 Jan 2025 22:39:07 +0530 Subject: [PATCH 13/14] feature-test: difference constraints logic, test --- .../0012_DifferenceConstraintsShortestPaths.h | 4 +- ...0012_DifferenceConstraintsShortestPaths.cc | 49 ++++++++++++++++++- Tests/0000_CommonUtilities/UnitTestHelper.h | 2 +- .../0005_HamiltonianPathAndCycleTest.cc | 2 +- ..._DifferenceConstraintsShortestPathsTest.cc | 33 +++++++++++++ 5 files changed, 85 insertions(+), 5 deletions(-) diff --git a/Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h b/Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h index f34d1e1..9c40f3a 100644 --- a/Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h +++ b/Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h @@ -36,9 +36,9 @@ namespace DifferenceConstraintsShortestPaths void InitializeSingleSource(Node* sourceNode); void Relax(Edge* edge); - public: void PushAllDirectedEdges(vector> vectorA, vector vectorX, vector vectorB); - + bool FindDifferenceConstraintsSolutionBellmanFord(); + vector GetDifferenceConstrtaintsSolution(); }; } \ No newline at end of file diff --git a/SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc b/SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc index 2e48f2b..34330f9 100644 --- a/SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc +++ b/SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc @@ -62,7 +62,7 @@ namespace DifferenceConstraintsShortestPaths // Graph Public Member Methods void Graph::PushAllDirectedEdges(vector> vectorA, vector vectorX, vector vectorB) { - // Creating the Graph + // Creating the Actual Graph string valueU = ""; string valueV = ""; int weight = 0; @@ -82,5 +82,52 @@ namespace DifferenceConstraintsShortestPaths weight = vectorB[i]; this->PushDirectedEdge(valueU, valueV, weight); } + + // Creating all the edges from the additional vertex + valueU = ""; + valueV = ""; + weight = 0; + for (int i = 0; i < vectorX.size(); i++) + { + valueV = vectorX[i]; + this->PushDirectedEdge(valueU, valueV, weight); + } + } + + bool Graph::FindDifferenceConstraintsSolutionBellmanFord() + { + Node* source = this->_nodeMap[""]; + + this->InitializeSingleSource(source); + + for (int i = 0; i < this->_nodeMap.size(); i++) + { + for (auto& edge : this->_edgeList) + { + this->Relax(edge); + } + } + + for (auto& edge : this->_edgeList) + { + if (edge->nodeV->distance > (edge->nodeU->distance + edge->weight)) + { + return false; + } + } + return true; + } + + vector Graph::GetDifferenceConstrtaintsSolution() + { + vector result; + for (auto& node : this->_nodeMap) + { + if (node.second->data != "") + { + result.push_back(node.second->distance); + } + } + return result; } } \ No newline at end of file diff --git a/Tests/0000_CommonUtilities/UnitTestHelper.h b/Tests/0000_CommonUtilities/UnitTestHelper.h index c903d36..6d8a5ed 100644 --- a/Tests/0000_CommonUtilities/UnitTestHelper.h +++ b/Tests/0000_CommonUtilities/UnitTestHelper.h @@ -109,7 +109,7 @@ class UnitTestHelper } template - bool NormalizeCyclesAnCompare(vector data1, vector data2) + bool NormalizeCyclesAndCompare(vector data1, vector data2) { if (data1.size() != data2.size()) { diff --git a/Tests/0003_Graph/0005_HamiltonianPathAndCycleTest.cc b/Tests/0003_Graph/0005_HamiltonianPathAndCycleTest.cc index 386825d..d46a651 100644 --- a/Tests/0003_Graph/0005_HamiltonianPathAndCycleTest.cc +++ b/Tests/0003_Graph/0005_HamiltonianPathAndCycleTest.cc @@ -28,6 +28,6 @@ namespace HamiltonianPathAndCycle ASSERT_TRUE(isHamiltonianCyclePresent); ASSERT_TRUE(isHamiltonianPathPresent); - ASSERT_TRUE(unitTestHelper.NormalizeCyclesAnCompare(hamiltonianPathActualResult, hamiltonianPathExpectedResult)); + ASSERT_TRUE(unitTestHelper.NormalizeCyclesAndCompare(hamiltonianPathActualResult, hamiltonianPathExpectedResult)); } } \ No newline at end of file diff --git a/Tests/0003_Graph/0012_DifferenceConstraintsShortestPathsTest.cc b/Tests/0003_Graph/0012_DifferenceConstraintsShortestPathsTest.cc index e69de29..2ae1fd0 100644 --- a/Tests/0003_Graph/0012_DifferenceConstraintsShortestPathsTest.cc +++ b/Tests/0003_Graph/0012_DifferenceConstraintsShortestPathsTest.cc @@ -0,0 +1,33 @@ +#include +#include"../Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h" +#include"../0000_CommonUtilities/UnitTestHelper.h" +using namespace std; + +namespace DifferenceConstraintsShortestPaths +{ + UnitTestHelper unitTestHelper; + + TEST(DifferenceConstraints, SimpleGraph) + { + Graph graph; + + vector> vectorA = + { + {1, -1, 0, 0, 0}, + {1, 0, 0, 0, -1}, + {0, 1, 0, 0, -1}, + {-1, 0, 1, 0, 0}, + {-1, 0, 0, 1, 0}, + {0, 0, -1, 1, 0}, + {0, 0, -1, 0, 1}, + {0, 0, 0, -1, 1}, + }; + vector vectorX = { "v1", "v2", "v3", "v4", "v5" }; + vector vectorB = {0, -1, 1, 5, 4, -1, -3, -3}; + string expectedSolution = "-5 -3 0 -1 -4"; + graph.PushAllDirectedEdges(vectorA, vectorX, vectorB); + + ASSERT_TRUE(graph.FindDifferenceConstraintsSolutionBellmanFord()); + ASSERT_EQ(unitTestHelper.SerializeVectorToString(graph.GetDifferenceConstrtaintsSolution()), expectedSolution); + } +} \ No newline at end of file From 7e2e3bf6b20e3091921208f316eed10538eacd25 Mon Sep 17 00:00:00 2001 From: Debashis Nandi Date: Wed, 15 Jan 2025 01:11:41 +0530 Subject: [PATCH 14/14] fix: diff constraints test --- .../0012_DifferenceConstraintsShortestPaths.h | 3 +-- ...0012_DifferenceConstraintsShortestPaths.cc | 6 ++--- Tests/0000_CommonUtilities/UnitTestHelper.h | 24 ++++++++++++++++++- ..._DifferenceConstraintsShortestPathsTest.cc | 11 +++++++-- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h b/Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h index 9c40f3a..683dfa2 100644 --- a/Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h +++ b/Headers/0003_Graph/0012_DifferenceConstraintsShortestPaths.h @@ -27,7 +27,6 @@ namespace DifferenceConstraintsShortestPaths class Graph { private: - Node* startingNode; map> _adjlist; map _nodeMap; vector _edgeList; @@ -39,6 +38,6 @@ namespace DifferenceConstraintsShortestPaths public: void PushAllDirectedEdges(vector> vectorA, vector vectorX, vector vectorB); bool FindDifferenceConstraintsSolutionBellmanFord(); - vector GetDifferenceConstrtaintsSolution(); + vector> GetDifferenceConstrtaintsSolution(); }; } \ No newline at end of file diff --git a/SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc b/SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc index 34330f9..20b7784 100644 --- a/SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc +++ b/SourceCodes/0003_Graph/0012_DifferenceConstraintsShortestPaths.cc @@ -118,14 +118,14 @@ namespace DifferenceConstraintsShortestPaths return true; } - vector Graph::GetDifferenceConstrtaintsSolution() + vector> Graph::GetDifferenceConstrtaintsSolution() { - vector result; + vector> result; for (auto& node : this->_nodeMap) { if (node.second->data != "") { - result.push_back(node.second->distance); + result.push_back({ node.second->data, node.second->distance }); } } return result; diff --git a/Tests/0000_CommonUtilities/UnitTestHelper.h b/Tests/0000_CommonUtilities/UnitTestHelper.h index 6d8a5ed..6e3509e 100644 --- a/Tests/0000_CommonUtilities/UnitTestHelper.h +++ b/Tests/0000_CommonUtilities/UnitTestHelper.h @@ -73,7 +73,6 @@ class UnitTestHelper return result; } - // This helper method is used to sort the vector of vectors of a particular typename. // Each inner vector is sorted first. // Then each of them are sorted by their first element, in increasing order. @@ -158,4 +157,27 @@ class UnitTestHelper }); return data; } + + template + string SortVectorOfPairAndSerialize(vector> data) + { + // Sorting the vector in non-decreasing order on typename T1 + sort(data.begin(), data.end(), [](const pair& pair1, const pair& pair2) + { + return pair1.first < pair2.first; + }); + + // Serializing the vector to string + string result = ""; + for (auto& iterator : data) + { + result += iterator.first + "(" + to_string(iterator.second) + ")" + " "; + } + + if (!result.empty()) + { + result.pop_back(); + } + return result; + } }; \ No newline at end of file diff --git a/Tests/0003_Graph/0012_DifferenceConstraintsShortestPathsTest.cc b/Tests/0003_Graph/0012_DifferenceConstraintsShortestPathsTest.cc index 2ae1fd0..04b293e 100644 --- a/Tests/0003_Graph/0012_DifferenceConstraintsShortestPathsTest.cc +++ b/Tests/0003_Graph/0012_DifferenceConstraintsShortestPathsTest.cc @@ -24,10 +24,17 @@ namespace DifferenceConstraintsShortestPaths }; vector vectorX = { "v1", "v2", "v3", "v4", "v5" }; vector vectorB = {0, -1, 1, 5, 4, -1, -3, -3}; - string expectedSolution = "-5 -3 0 -1 -4"; + vector> expectedSolution = + { + {"v2", -3}, + {"v5", -4}, + {"v1", -5}, + {"v4", -1}, + {"v3", 0}, + }; graph.PushAllDirectedEdges(vectorA, vectorX, vectorB); ASSERT_TRUE(graph.FindDifferenceConstraintsSolutionBellmanFord()); - ASSERT_EQ(unitTestHelper.SerializeVectorToString(graph.GetDifferenceConstrtaintsSolution()), expectedSolution); + ASSERT_EQ(unitTestHelper.SortVectorOfPairAndSerialize(graph.GetDifferenceConstrtaintsSolution()), unitTestHelper.SortVectorOfPairAndSerialize(expectedSolution)); } } \ No newline at end of file