From e58561a1aa59f05afa8bc509ff849490daee35aa Mon Sep 17 00:00:00 2001 From: sbaldu Date: Thu, 28 Sep 2023 10:11:31 +0200 Subject: [PATCH 1/4] Add functions returning set of neighbouring edges --- include/CXXGraph/Graph/Graph.hpp | 93 +++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/include/CXXGraph/Graph/Graph.hpp b/include/CXXGraph/Graph/Graph.hpp index 6dc5bdad3..115f47fae 100644 --- a/include/CXXGraph/Graph/Graph.hpp +++ b/include/CXXGraph/Graph/Graph.hpp @@ -341,6 +341,46 @@ class Graph { */ virtual const std::unordered_set>, nodeHash> inOutNeighbors(shared> node) const; + /** + * \brief + * \brief This function generates a set of Edges going out of a node + * in any graph + * + * @param Pointer to the node + * + */ + virtual const std::unordered_set>, nodeHash> outEdges( + const Node *node) const; + /** + * \brief + * \brief This function generates a set of Edges going out of a node + * in any graph + * + * @param Shared pointer to the node + * + */ + virtual const std::unordered_set>, nodeHash> outEdges( + shared> node) const; + /** + * \brief + * \brief This function generates a set of Edges coming in or going out of + * a node in any graph + * + * @param Pointer to the node + * + */ + virtual const std::unordered_set>, nodeHash> + inOutEdges(const Node *node) const; + /** + * \brief + * \brief This function generates a set of Edges coming in or going out of + * a node in any graph + * + * @param Shared pointer to the node + * + */ + virtual const std::unordered_set>, nodeHash> + inOutEdges(shared> node) const; /** * @brief This function finds the subset of given a nodeId * Subset is stored in a map where keys are the hash-id of the node & values @@ -1091,7 +1131,7 @@ std::unordered_set>, nodeHash> Graph::nodeSet() { std::const_pointer_cast>(edgeSetIt->getNodePair().second)); } for (auto &isNodeIt : isolatedNodesSet) { - nodeSet.insert(std::const_pointer_cast>(isNodeIt)); + nodeSet.insert(std::const_pointer_cast>(isNodeIt)); } return nodeSet; @@ -1680,6 +1720,57 @@ Graph::inOutNeighbors(shared> node) const { return inOutNeighbors; } +template +const std::unordered_set>, edgeHash> outEdges( + const Node *node) const { + auto node_shared = make_shared>(*node); + + return outEdges(node_shared); +} + +template +const std::unordered_set>, edgeHash> outEdges( + shared> node) const { + if (cachedAdjMatrix->find(node) == cachedAdjMatrix->end()) { + return std::unordered_set>, nodeHash>(); + } + auto nodeEdgePairs = cachedAdjMatrix->at(node); + + std::unordered_set>, nodeHash> outEdges; + for (auto pair : nodeEdgePairs) { + if (pair.second->isDirected().has_value() && + pair.second->isDirected().value()) { + outEdges.insert(pair.second); + } + } + + return outEdges; +} + +template +const std::unordered_set>, edgeHash> inOutEdges( + const Node *node) const { + auto node_shared = make_shared>(*node); + + return outEdges(node_shared); +} + +template +const std::unordered_set>, edgeHash> inOutEdges( + shared> node) const { + if (cachedAdjMatrix->find(node) == cachedAdjMatrix->end()) { + return std::unordered_set>, nodeHash>(); + } + auto nodeEdgePairs = cachedAdjMatrix->at(node); + + std::unordered_set>, nodeHash> outEdges; + for (auto pair : nodeEdgePairs) { + outEdges.insert(pair.second); + } + + return outEdges; +} + template const DijkstraResult Graph::dijkstra(const Node &source, const Node &target) const { From 2aa8063bc550c0a700199972e668491824a9768e Mon Sep 17 00:00:00 2001 From: sbaldu Date: Thu, 28 Sep 2023 14:25:24 +0200 Subject: [PATCH 2/4] Fix typos in inOutEdges functions --- include/CXXGraph/Graph/Graph.hpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/include/CXXGraph/Graph/Graph.hpp b/include/CXXGraph/Graph/Graph.hpp index 115f47fae..63bc49dca 100644 --- a/include/CXXGraph/Graph/Graph.hpp +++ b/include/CXXGraph/Graph/Graph.hpp @@ -349,7 +349,7 @@ class Graph { * @param Pointer to the node * */ - virtual const std::unordered_set>, nodeHash> outEdges( + virtual const std::unordered_set>, edgeHash> outEdges( const Node *node) const; /** * \brief @@ -359,7 +359,7 @@ class Graph { * @param Shared pointer to the node * */ - virtual const std::unordered_set>, nodeHash> outEdges( + virtual const std::unordered_set>, edgeHash> outEdges( shared> node) const; /** * \brief @@ -369,7 +369,7 @@ class Graph { * @param Pointer to the node * */ - virtual const std::unordered_set>, nodeHash> + virtual const std::unordered_set>, edgeHash> inOutEdges(const Node *node) const; /** * \brief @@ -379,7 +379,7 @@ class Graph { * @param Shared pointer to the node * */ - virtual const std::unordered_set>, nodeHash> + virtual const std::unordered_set>, edgeHash> inOutEdges(shared> node) const; /** * @brief This function finds the subset of given a nodeId @@ -1721,7 +1721,7 @@ Graph::inOutNeighbors(shared> node) const { } template -const std::unordered_set>, edgeHash> outEdges( +const std::unordered_set>, edgeHash> Graph::outEdges( const Node *node) const { auto node_shared = make_shared>(*node); @@ -1729,14 +1729,14 @@ const std::unordered_set>, edgeHash> outEdges( } template -const std::unordered_set>, edgeHash> outEdges( +const std::unordered_set>, edgeHash> Graph::outEdges( shared> node) const { if (cachedAdjMatrix->find(node) == cachedAdjMatrix->end()) { - return std::unordered_set>, nodeHash>(); + return std::unordered_set>, edgeHash>(); } auto nodeEdgePairs = cachedAdjMatrix->at(node); - std::unordered_set>, nodeHash> outEdges; + std::unordered_set>, edgeHash> outEdges; for (auto pair : nodeEdgePairs) { if (pair.second->isDirected().has_value() && pair.second->isDirected().value()) { @@ -1748,22 +1748,22 @@ const std::unordered_set>, edgeHash> outEdges( } template -const std::unordered_set>, edgeHash> inOutEdges( - const Node *node) const { +const std::unordered_set>, edgeHash> +Graph::inOutEdges(const Node *node) const { auto node_shared = make_shared>(*node); return outEdges(node_shared); } template -const std::unordered_set>, edgeHash> inOutEdges( - shared> node) const { +const std::unordered_set>, edgeHash> +Graph::inOutEdges(shared> node) const { if (cachedAdjMatrix->find(node) == cachedAdjMatrix->end()) { - return std::unordered_set>, nodeHash>(); + return std::unordered_set>, edgeHash>(); } auto nodeEdgePairs = cachedAdjMatrix->at(node); - std::unordered_set>, nodeHash> outEdges; + std::unordered_set>, edgeHash> outEdges; for (auto pair : nodeEdgePairs) { outEdges.insert(pair.second); } From f67c02a41cce52d4648683c81527243718fa81e6 Mon Sep 17 00:00:00 2001 From: sbaldu Date: Thu, 28 Sep 2023 14:40:43 +0200 Subject: [PATCH 3/4] Add tests for inOutEdges functions. Formatting. --- test/GraphTest.cpp | 243 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 220 insertions(+), 23 deletions(-) diff --git a/test/GraphTest.cpp b/test/GraphTest.cpp index e1a1460af..720f965bf 100644 --- a/test/GraphTest.cpp +++ b/test/GraphTest.cpp @@ -121,18 +121,18 @@ TEST(GraphTest, FindEdge_Test) { edgeSet.insert(make_shared>(edge2)); CXXGraph::Graph graph(edgeSet); size_t edgeId = 0; - ASSERT_TRUE(graph.findEdge(&node1,&node2,edgeId)); + ASSERT_TRUE(graph.findEdge(&node1, &node2, edgeId)); CXXGraph::UndirectedEdge edge3(3, node1, node3); /* adding edge using addEdge() */ graph.addEdge(make_shared>(edge3)); - ASSERT_TRUE(graph.findEdge(&node1,&node3,edgeId)); - ASSERT_TRUE(graph.findEdge(&node3,&node1,edgeId)); + ASSERT_TRUE(graph.findEdge(&node1, &node3, edgeId)); + ASSERT_TRUE(graph.findEdge(&node3, &node1, edgeId)); CXXGraph::DirectedEdge edge4(4, node1, node5); graph.addEdge(make_shared>(edge4)); - ASSERT_TRUE(graph.findEdge(&node1,&node5,edgeId)); - ASSERT_FALSE(graph.findEdge(&node5,&node1,edgeId)); + ASSERT_TRUE(graph.findEdge(&node1, &node5, edgeId)); + ASSERT_FALSE(graph.findEdge(&node5, &node1, edgeId)); /* removing edge using removeEdge() */ @@ -141,16 +141,16 @@ TEST(GraphTest, FindEdge_Test) { CXXGraph::DirectedWeightedEdge edge6(8, node2, node5, 10); /* adding edge using addEdge() */ - + graph.addEdge(&edge5); graph.addEdge(&edge6); - ASSERT_FALSE(graph.findEdge(&node2,&node3,edgeId)); - ASSERT_FALSE(graph.findEdge(&node3,&node2,edgeId)); + ASSERT_FALSE(graph.findEdge(&node2, &node3, edgeId)); + ASSERT_FALSE(graph.findEdge(&node3, &node2, edgeId)); /* Test for empty graph */ CXXGraph::Graph graph2; - ASSERT_FALSE(graph2.findEdge(&node2,&node3,edgeId)); + ASSERT_FALSE(graph2.findEdge(&node2, &node3, edgeId)); } TEST(GraphTest, RawAddEdge_1) { @@ -268,16 +268,21 @@ TEST(GraphTest, DirectedEdge_hashequality) { CXXGraph::DirectedEdge edge11(11, node7, node2); CXXGraph::T_EdgeSet edges; - auto addEdge = [&](CXXGraph::DirectedEdge& edge) - { + auto addEdge = [&](CXXGraph::DirectedEdge &edge) { size_t currSize = edges.size(); - auto sharedEdge = CXXGraph::make_shared>(edge.getId(), edge.getFrom(), edge.getTo()); + auto sharedEdge = CXXGraph::make_shared>( + edge.getId(), edge.getFrom(), edge.getTo()); edges.insert(sharedEdge); - if ((currSize + 1) != edges.size()) - { - std::cout << "Skipped " << edge.getNodePair().first->getUserId() << " --> " << edge.getNodePair().second->getUserId() << " (hash: " << CXXGraph::edgeHash{}(sharedEdge) << ")" << std::endl; + if ((currSize + 1) != edges.size()) { + std::cout << "Skipped " << edge.getNodePair().first->getUserId() + << " --> " << edge.getNodePair().second->getUserId() + << " (hash: " << CXXGraph::edgeHash{}(sharedEdge) << ")" + << std::endl; } else { - std::cout << "Added " << edge.getNodePair().first->getUserId() << " --> " << edge.getNodePair().second->getUserId() << " (hash: " << CXXGraph::edgeHash{}(sharedEdge) << ")" << std::endl; + std::cout << "Added " << edge.getNodePair().first->getUserId() << " --> " + << edge.getNodePair().second->getUserId() + << " (hash: " << CXXGraph::edgeHash{}(sharedEdge) << ")" + << std::endl; } }; @@ -438,7 +443,7 @@ TEST(GraphTest, set_data) { } } -TEST(GraphTest, test_outEdges) { +TEST(GraphTest, test_outNodes) { CXXGraph::Node node1("1", 1); CXXGraph::Node node2("2", 2); CXXGraph::Node node3("3", 3); @@ -497,7 +502,7 @@ TEST(GraphTest, test_outEdges) { } // Test the overload that takes shared_ptr as input -TEST(GraphTest, test_outEdges_shared) { +TEST(GraphTest, test_outNodes_shared) { CXXGraph::Node node1("1", 1); CXXGraph::Node node2("2", 2); CXXGraph::Node node3("3", 3); @@ -547,7 +552,7 @@ TEST(GraphTest, test_outEdges_shared) { } } -TEST(GraphTest, test_inOutEdges) { +TEST(GraphTest, test_inOutNodes) { CXXGraph::Node node1("1", 1); CXXGraph::Node node2("2", 2); CXXGraph::Node node3("3", 3); @@ -594,7 +599,7 @@ TEST(GraphTest, test_inOutEdges) { } // Test the overload that takes shared_ptr as input -TEST(GraphTest, test_inOutEdges_shared) { +TEST(GraphTest, test_inOutNodes_shared) { CXXGraph::Node node1("1", 1); CXXGraph::Node node2("2", 2); CXXGraph::Node node3("3", 3); @@ -634,6 +639,196 @@ TEST(GraphTest, test_inOutEdges_shared) { } } +TEST(InOutNodesTest, test_outEdges) { + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 2); + CXXGraph::Node node3("3", 3); + CXXGraph::Node node4("4", 4); + CXXGraph::Node node5("5", 5); + CXXGraph::Node node6("6", 6); + CXXGraph::Node node7("7", 7); + CXXGraph::Node node8("8", 8); + CXXGraph::DirectedEdge edge1(1, node1, node2); + CXXGraph::DirectedEdge edge2(2, node1, node3); + CXXGraph::DirectedEdge edge3(3, node2, node4); + CXXGraph::DirectedEdge edge4(4, node2, node5); + CXXGraph::DirectedEdge edge5(5, node3, node4); + CXXGraph::DirectedEdge edge6(6, node3, node5); + CXXGraph::DirectedEdge edge7(7, node4, node6); + CXXGraph::DirectedEdge edge8(8, node4, node7); + CXXGraph::DirectedEdge edge9(7, node5, node6); + CXXGraph::DirectedEdge edge10(8, node5, node7); + CXXGraph::DirectedEdge edge11(8, node6, node8); + CXXGraph::DirectedEdge edge12(8, node7, node8); + CXXGraph::T_EdgeSet edgeSet; + edgeSet.insert(make_shared>(edge1)); + edgeSet.insert(make_shared>(edge2)); + edgeSet.insert(make_shared>(edge3)); + edgeSet.insert(make_shared>(edge4)); + edgeSet.insert(make_shared>(edge5)); + edgeSet.insert(make_shared>(edge6)); + edgeSet.insert(make_shared>(edge7)); + edgeSet.insert(make_shared>(edge8)); + edgeSet.insert(make_shared>(edge9)); + edgeSet.insert(make_shared>(edge10)); + edgeSet.insert(make_shared>(edge11)); + edgeSet.insert(make_shared>(edge12)); + CXXGraph::Graph graph(edgeSet); + + for (auto x : graph.outEdges(&node1)) { + ASSERT_TRUE(x == make_shared>(edge1) || + x == make_shared>(edge2)); + } + + auto node2_shared = make_shared>(node2); + for (auto x : graph.outEdges(&node2)) { + ASSERT_TRUE(x == make_shared>(edge3) || + x == make_shared>(edge4)); + ASSERT_FALSE(x == make_shared>(edge1)); + } +} + +TEST(InOutNodesTest, test_outEdges_shared) { + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 2); + CXXGraph::Node node3("3", 3); + CXXGraph::Node node4("4", 4); + CXXGraph::Node node5("5", 5); + CXXGraph::Node node6("6", 6); + CXXGraph::Node node7("7", 7); + CXXGraph::Node node8("8", 8); + CXXGraph::DirectedEdge edge1(1, node1, node2); + CXXGraph::DirectedEdge edge2(2, node1, node3); + CXXGraph::DirectedEdge edge3(3, node2, node4); + CXXGraph::DirectedEdge edge4(4, node2, node5); + CXXGraph::DirectedEdge edge5(5, node3, node4); + CXXGraph::DirectedEdge edge6(6, node3, node5); + CXXGraph::DirectedEdge edge7(7, node4, node6); + CXXGraph::DirectedEdge edge8(8, node4, node7); + CXXGraph::DirectedEdge edge9(7, node5, node6); + CXXGraph::DirectedEdge edge10(8, node5, node7); + CXXGraph::DirectedEdge edge11(8, node6, node8); + CXXGraph::DirectedEdge edge12(8, node7, node8); + CXXGraph::T_EdgeSet edgeSet; + edgeSet.insert(make_shared>(edge1)); + edgeSet.insert(make_shared>(edge2)); + edgeSet.insert(make_shared>(edge3)); + edgeSet.insert(make_shared>(edge4)); + edgeSet.insert(make_shared>(edge5)); + edgeSet.insert(make_shared>(edge6)); + edgeSet.insert(make_shared>(edge7)); + edgeSet.insert(make_shared>(edge8)); + edgeSet.insert(make_shared>(edge9)); + edgeSet.insert(make_shared>(edge10)); + edgeSet.insert(make_shared>(edge11)); + edgeSet.insert(make_shared>(edge12)); + CXXGraph::Graph graph(edgeSet); + + auto node1_shared = make_shared>(node1); + for (auto x : graph.outEdges(node1_shared)) { + ASSERT_TRUE(x == make_shared>(edge1) || + x == make_shared>(edge2)); + } + + auto node2_shared = make_shared>(node2); + for (auto x : graph.outEdges(node2_shared)) { + ASSERT_TRUE(x == make_shared>(edge3) || + x == make_shared>(edge4)); + ASSERT_FALSE(x == make_shared>(edge1)); + } +} + +TEST(InOutNodesTest, test_inOutEdges) { + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 2); + CXXGraph::Node node3("3", 3); + CXXGraph::Node node4("4", 4); + CXXGraph::Node node5("5", 5); + CXXGraph::Node node6("6", 6); + CXXGraph::Node node7("7", 7); + CXXGraph::Node node8("8", 8); + CXXGraph::UndirectedEdge edge1(1, node1, node2); + CXXGraph::UndirectedEdge edge2(2, node1, node3); + CXXGraph::UndirectedEdge edge3(3, node2, node3); + CXXGraph::UndirectedEdge edge4(4, node2, node4); + CXXGraph::UndirectedEdge edge5(5, node4, node5); + CXXGraph::UndirectedEdge edge6(6, node4, node6); + CXXGraph::UndirectedEdge edge7(7, node6, node7); + CXXGraph::UndirectedEdge edge8(8, node6, node8); + CXXGraph::T_EdgeSet edgeSet; + edgeSet.insert(make_shared>(edge1)); + edgeSet.insert(make_shared>(edge2)); + edgeSet.insert(make_shared>(edge3)); + edgeSet.insert(make_shared>(edge4)); + edgeSet.insert(make_shared>(edge5)); + edgeSet.insert(make_shared>(edge6)); + edgeSet.insert(make_shared>(edge7)); + edgeSet.insert(make_shared>(edge8)); + CXXGraph::Graph graph(edgeSet); + + for (auto x : graph.inOutEdges(&node1)) { + ASSERT_TRUE(x == make_shared>(edge1) || + x == make_shared>(edge2)); + } + + for (auto x : graph.inOutEdges(&node6)) { + ASSERT_TRUE(x == make_shared>(edge6) || + x == make_shared>(edge7) || + x == make_shared>(edge8)); + } + + for (auto x : graph.inOutEdges(&node7)) { + ASSERT_TRUE(x == make_shared>(edge7)); + } +} + +TEST(InOutNodesTest, test_inOutEdges_shared) { + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 2); + CXXGraph::Node node3("3", 3); + CXXGraph::Node node4("4", 4); + CXXGraph::Node node5("5", 5); + CXXGraph::Node node6("6", 6); + CXXGraph::Node node7("7", 7); + CXXGraph::Node node8("8", 8); + CXXGraph::UndirectedEdge edge1(1, node1, node2); + CXXGraph::UndirectedEdge edge2(2, node1, node3); + CXXGraph::UndirectedEdge edge3(3, node2, node3); + CXXGraph::UndirectedEdge edge4(4, node2, node4); + CXXGraph::UndirectedEdge edge5(5, node4, node5); + CXXGraph::UndirectedEdge edge6(6, node4, node6); + CXXGraph::UndirectedEdge edge7(7, node6, node7); + CXXGraph::UndirectedEdge edge8(8, node6, node8); + CXXGraph::T_EdgeSet edgeSet; + edgeSet.insert(make_shared>(edge1)); + edgeSet.insert(make_shared>(edge2)); + edgeSet.insert(make_shared>(edge3)); + edgeSet.insert(make_shared>(edge4)); + edgeSet.insert(make_shared>(edge5)); + edgeSet.insert(make_shared>(edge6)); + edgeSet.insert(make_shared>(edge7)); + edgeSet.insert(make_shared>(edge8)); + CXXGraph::Graph graph(edgeSet); + + auto node1_shared = make_shared>(node1); + for (auto x : graph.inOutEdges(node1_shared)) { + ASSERT_TRUE(x == make_shared>(edge1) || + x == make_shared>(edge2)); + } + + auto node6_shared = make_shared>(node6); + for (auto x : graph.inOutEdges(node6_shared)) { + ASSERT_TRUE(x == make_shared>(edge6) || + x == make_shared>(edge7) || + x == make_shared>(edge8)); + } + + auto node7_shared = make_shared>(node7); + for (auto x : graph.inOutEdges(node7_shared)) { + ASSERT_TRUE(x == make_shared>(edge7)); + } +} + TEST(ReverseDirectedGraphTest, test_function) { CXXGraph::Node node1("1", 1); CXXGraph::Node node2("2", 2); @@ -653,11 +848,13 @@ TEST(ReverseDirectedGraphTest, test_function) { // Check edges auto originalSet = graph.getEdgeSet(); auto reverseSet = reverseGraph.getEdgeSet(); - for (auto originalEdge: originalSet) { + for (auto originalEdge : originalSet) { for (auto reverseEdge : reverseSet) { if (originalEdge->getId() == reverseEdge->getId()) { - ASSERT_TRUE(originalEdge->getNodePair().first->getUserId() == reverseEdge->getNodePair().second->getUserId() && - originalEdge->getNodePair().second->getUserId() == reverseEdge->getNodePair().first->getUserId()); + ASSERT_TRUE(originalEdge->getNodePair().first->getUserId() == + reverseEdge->getNodePair().second->getUserId() && + originalEdge->getNodePair().second->getUserId() == + reverseEdge->getNodePair().first->getUserId()); } } } From 84bfeb6735d2103305f00ff40f592e2355400370 Mon Sep 17 00:00:00 2001 From: sbaldu Date: Thu, 28 Sep 2023 17:21:07 +0200 Subject: [PATCH 4/4] Improve coverage for tests of inOutEdges functions --- test/GraphTest.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/GraphTest.cpp b/test/GraphTest.cpp index 720f965bf..3641c8d1f 100644 --- a/test/GraphTest.cpp +++ b/test/GraphTest.cpp @@ -736,6 +736,12 @@ TEST(InOutNodesTest, test_outEdges_shared) { x == make_shared>(edge4)); ASSERT_FALSE(x == make_shared>(edge1)); } + + // Check the result for a node that does not exist in the graph + CXXGraph::Node node9("9", 9); + auto node9_shared = make_shared>(node9); + auto edges = graph.outEdges(node9_shared); + ASSERT_EQ(edges.size(), 0); } TEST(InOutNodesTest, test_inOutEdges) { @@ -827,6 +833,12 @@ TEST(InOutNodesTest, test_inOutEdges_shared) { for (auto x : graph.inOutEdges(node7_shared)) { ASSERT_TRUE(x == make_shared>(edge7)); } + + // Check the result for a node that does not exist in the graph + CXXGraph::Node node9("9", 9); + auto node9_shared = make_shared>(node9); + auto edges = graph.inOutEdges(node9_shared); + ASSERT_EQ(edges.size(), 0); } TEST(ReverseDirectedGraphTest, test_function) {