diff --git a/include/Graph/Graph.hpp b/include/Graph/Graph.hpp index eee3478a4..4099f6052 100644 --- a/include/Graph/Graph.hpp +++ b/include/Graph/Graph.hpp @@ -101,6 +101,8 @@ class Graph { private: T_EdgeSet edgeSet = {}; + shared> cachedAdjMatrix; + // Private non-const getter for the set of nodes std::unordered_set>, nodeHash> nodeSet(); @@ -130,7 +132,7 @@ class Graph { #endif public: - Graph() = default; + Graph(); Graph(const T_EdgeSet &edgeSet); virtual ~Graph() = default; /** @@ -248,7 +250,9 @@ class Graph { * corrispondent to the link * Note: No Thread Safe */ - virtual const std::shared_ptr> getAdjMatrix() const; + virtual shared> getAdjMatrix() const; + + virtual void cacheAdjMatrix(); /** * \brief This function generates a set of nodes linked to the provided node * in a directed graph @@ -733,11 +737,19 @@ class Graph { const AdjacencyMatrix &adj); }; +template +Graph::Graph() { + /* Caching the adjacency matrix */ + cacheAdjMatrix(); +} + template Graph::Graph(const T_EdgeSet &edgeSet) { for (auto edgeIt : edgeSet) { this->edgeSet.insert(edgeIt); } + /* Caching the adjacency matrix */ + cacheAdjMatrix(); } template @@ -751,6 +763,8 @@ void Graph::setEdgeSet(const T_EdgeSet &edgeSet) { for (auto edgeIt : edgeSet) { this->edgeSet.insert(edgeIt); } + /* Caching the adjacency matrix */ + cacheAdjMatrix(); } template @@ -759,17 +773,29 @@ void Graph::addEdge(const Edge *edge) { if (edge->isWeighted().has_value() && edge->isWeighted().value()) { auto edge_shared = make_shared>(*edge); this->edgeSet.insert(edge_shared); + std::pair>, shared>> elem = {edge_shared->getNodePair().second, edge_shared}; + (*cachedAdjMatrix)[edge_shared->getNodePair().first].push_back(std::move(elem)); } else { auto edge_shared = make_shared>(*edge); this->edgeSet.insert(edge_shared); + std::pair>, shared>> elem = {edge_shared->getNodePair().second, edge_shared}; + (*cachedAdjMatrix)[edge_shared->getNodePair().first].push_back(std::move(elem)); } } else { if (edge->isWeighted().has_value() && edge->isWeighted().value()) { auto edge_shared = make_shared>(*edge); this->edgeSet.insert(edge_shared); + std::pair>, shared>> elem = {edge_shared->getNodePair().second, edge_shared}; + (*cachedAdjMatrix)[edge_shared->getNodePair().first].push_back(std::move(elem)); + std::pair>, shared>> elem1 = {edge_shared->getNodePair().first, edge_shared}; + (*cachedAdjMatrix)[edge_shared->getNodePair().second].push_back(std::move(elem1)); } else { auto edge_shared = make_shared>(*edge); this->edgeSet.insert(edge_shared); + std::pair>, shared>> elem = {edge_shared->getNodePair().second, edge_shared}; + (*cachedAdjMatrix)[edge_shared->getNodePair().first].push_back(std::move(elem)); + std::pair>, shared>> elem1 = {edge_shared->getNodePair().first, edge_shared}; + (*cachedAdjMatrix)[edge_shared->getNodePair().second].push_back(std::move(elem1)); } } } @@ -777,6 +803,17 @@ void Graph::addEdge(const Edge *edge) { template void Graph::addEdge(shared> edge) { this->edgeSet.insert(edge); + /* Adding new edge in cached adjacency matrix */ + if(edge.get()->isDirected().has_value() && edge.get()->isDirected().value()){ + std::pair>, shared>> elem = {edge.get()->getNodePair().second, edge}; + (*cachedAdjMatrix)[edge.get()->getNodePair().first].push_back(std::move(elem)); + } + else{ + std::pair>, shared>> elem = {edge.get()->getNodePair().second, edge}; + (*cachedAdjMatrix)[edge.get()->getNodePair().first].push_back(std::move(elem)); + std::pair>, shared>> elem1 = {edge.get()->getNodePair().first, edge}; + (*cachedAdjMatrix)[edge.get()->getNodePair().second].push_back(std::move(elem1)); + } } template @@ -788,6 +825,32 @@ void Graph::removeEdge(const unsigned long long edgeId) { [edgeOpt](const Edge *edge) { return (*(edgeOpt.value()) == *edge); })); */ edgeSet.erase(edgeSet.find(edgeOpt.value())); + int delIndex = -1; + int i = 0; + /* Removing the edge from the cached adjacency matrix */ + for(auto elem : (*cachedAdjMatrix)[edgeOpt.value().get()->getNodePair().first]){ + if(elem.second.get()->getId() == edgeId){ + delIndex = i; + break; + } + i++; + } + if(delIndex != -1){ + (*cachedAdjMatrix)[edgeOpt.value().get()->getNodePair().first].erase((*cachedAdjMatrix)[edgeOpt.value().get()->getNodePair().first].begin()+delIndex); + } + + delIndex = -1; + i = 0; + for(auto elem : (*cachedAdjMatrix)[edgeOpt.value().get()->getNodePair().second]){ + if(elem.second.get()->getId() == edgeId){ + delIndex = i; + break; + } + i++; + } + if(delIndex != -1){ + (*cachedAdjMatrix)[edgeOpt.value().get()->getNodePair().second].erase((*cachedAdjMatrix)[edgeOpt.value().get()->getNodePair().second].begin()+delIndex); + } } } @@ -805,7 +868,32 @@ bool Graph::findEdge(shared> v1, shared> v2, unsigned long long &id) const { // This could be made faster by looking for the edge hash, assuming we hash // based on node data, instead of a unique integer - for (auto e : this->edgeSet) { + if(cachedAdjMatrix.get() != NULL && cachedAdjMatrix->size() != 0){ + /* Searching for the edge using cached adjacency matrix */ + + for(auto elem : (*cachedAdjMatrix)[v1]){ + if(elem.first == v2){ + id = elem.second.get()->getId(); + return true; + } + } + } + else{ + /* Searching for the edge using edgeset */ + + for (auto e : this->edgeSet) { + if ((e->getNodePair().first == v1) && (e->getNodePair().second == v2)) { + id = e->getId(); + return true; + } + if (!e->isDirected() && + ((e->getNodePair().second == v1) && (e->getNodePair().first == v2))) { + id = e->getId(); + return true; + } + } + } + /*for (auto e : this->edgeSet) { if ((e->getNodePair().first == v1) && (e->getNodePair().second == v2)) { id = e->getId(); return true; @@ -815,7 +903,7 @@ bool Graph::findEdge(shared> v1, shared> v2, id = e->getId(); return true; } - } + }*/ id = 0; return false; @@ -1381,7 +1469,7 @@ std::shared_ptr>> Graph::eulerianPath() const { } template -const std::shared_ptr> Graph::getAdjMatrix() const { +shared> Graph::getAdjMatrix() const { auto adj = std::make_shared>(); auto addElementToAdjMatrix = [&adj](shared> nodeFrom, shared> nodeTo, @@ -1413,6 +1501,12 @@ const std::shared_ptr> Graph::getAdjMatrix() const { return adj; } +template +void Graph::cacheAdjMatrix() { + const auto adj = Graph::getAdjMatrix(); + this->cachedAdjMatrix = adj; +} + template const std::unordered_set>, nodeHash> Graph::outNeighbors(const Node *node) const { diff --git a/test/GraphTest.cpp b/test/GraphTest.cpp index 6ab495087..28e7aad59 100644 --- a/test/GraphTest.cpp +++ b/test/GraphTest.cpp @@ -105,6 +105,54 @@ TEST(GraphTest, GetNodeSet_2) { }) != nodeSet.end()); } +TEST(GraphTest, FindEdge_Test) { + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 2); + CXXGraph::Node node3("3", 3); + CXXGraph::Node node4("4", 2); + CXXGraph::Node node5("5", 3); + CXXGraph::UndirectedEdge edge(1, node1, node2); + CXXGraph::UndirectedEdge edge2(2, node2, node3); + CXXGraph::T_EdgeSet edgeSet; + + /* adding edges to the edgeset */ + + edgeSet.insert(make_shared>(edge)); + edgeSet.insert(make_shared>(edge2)); + CXXGraph::Graph graph(edgeSet); + unsigned long long edgeId = 0; + 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)); + 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)); + + /* removing edge using removeEdge() */ + + graph.removeEdge(2); + CXXGraph::UndirectedWeightedEdge edge5(7, node4, node5, 5); + 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)); + + /* Test for empty graph */ + + CXXGraph::Graph graph2; + ASSERT_FALSE(graph2.findEdge(&node2,&node3,edgeId)); +} + TEST(GraphTest, RawAddEdge_1) { CXXGraph::Node n1("a", 1); CXXGraph::Node n2("b", 1);