diff --git a/include/CXXGraph/Graph/Algorithm/isBipartiteGraph.hpp b/include/CXXGraph/Graph/Algorithm/isBipartiteGraph.hpp new file mode 100644 index 00000000..b7b7aa8c --- /dev/null +++ b/include/CXXGraph/Graph/Algorithm/isBipartiteGraph.hpp @@ -0,0 +1,91 @@ +/***********************************************************/ +/*** ______ ____ ______ _ ***/ +/*** / ___\ \/ /\ \/ / ___|_ __ __ _ _ __ | |__ ***/ +/*** | | \ / \ / | _| '__/ _` | '_ \| '_ \ ***/ +/*** | |___ / \ / \ |_| | | | (_| | |_) | | | | ***/ +/*** \____/_/\_\/_/\_\____|_| \__,_| .__/|_| |_| ***/ +/*** |_| ***/ +/***********************************************************/ +/*** Header-Only C++ Library for Graph ***/ +/*** Representation and Algorithms ***/ +/***********************************************************/ +/*** Author: ZigRazor ***/ +/*** E-Mail: zigrazor@gmail.com ***/ +/***********************************************************/ +/*** Collaboration: ----------- ***/ +/***********************************************************/ +/*** License: AGPL v3.0 ***/ +/***********************************************************/ + +#ifndef __CXXGRAPH_CHECK_ODD_NODES_CYCLE_H__ +#define __CXXGRAPH_CHECK_ODD_NODES_CYCLE_H__ + +#pragma once + +#include "CXXGraph/Graph/Graph_decl.h" + +namespace CXXGraph { + +template +class Graph { + public: + TopoSortResult checkOddNodesCycleDir() const; + + private: + void checkOddNodesCycleUtil(std::vector& visited, + std::vector& chainNo, int root, + int cycleLength, bool& isBiPartite) const; +}; + +template +TopoSortResult Graph::checkOddNodesCycleDir() const { + TopoSortResult result; + + // Check if the graph is undirected + if (isDirectedGraph()) { + result.errorMessage = ERR_UNDIR_GRAPH; // Error: Graph is directed + return result; + } + + const auto nodeSet = Graph::getNodeSet(); + std::vector visited(nodeSet.size(), 0); + std::vector chainNo(nodeSet.size(), -1); + bool isBiPartite = true; + + for (const auto& node : nodeSet) { + if (!visited[node->getId()]) { + visited[node->getId()] = 1; + checkOddNodesCycleUtil(visited, chainNo, node->getId(), 0, isBiPartite); + if (!isBiPartite) { + result.errorMessage = "The graph contains an odd-length cycle."; + return result; + } + } + } + + result.success = true; + return result; +} + +template +void Graph::checkOddNodesCycleUtil(std::vector& visited, + std::vector& chainNo, int root, + int cycleLength, + bool& isBiPartite) const { + chainNo[root] = cycleLength; + for (const auto& child : cachedAdjMatrix->find(root)) { + if (!visited[std::get<0>(child)->getId()]) { + visited[std::get<0>(child)->getId()] = 1; + checkOddNodesCycleUtil(visited, chainNo, std::get<0>(child)->getId(), + cycleLength + 1, isBiPartite); + if (!isBiPartite) return; + } else if (chainNo[root] == chainNo[std::get<0>(child)->getId()]) { + isBiPartite = false; + return; + } + } +} + +} // namespace CXXGraph + +#endif // __CXXGRAPH_CHECK_ODD_NODES_CYCLE_H__ diff --git a/include/CXXGraph/Graph/Graph.h b/include/CXXGraph/Graph/Graph.h index aedb55ee..74c71699 100644 --- a/include/CXXGraph/Graph/Graph.h +++ b/include/CXXGraph/Graph/Graph.h @@ -42,6 +42,7 @@ #include "CXXGraph/Graph/Algorithm/TopologicalSort_impl.hpp" #include "CXXGraph/Graph/Algorithm/TransitiveReduction_impl.hpp" #include "CXXGraph/Graph/Algorithm/welshPowellColoring_impl.hpp" +#include "CXXGraph/Graph/Algorithm/isBipartiteGraph.hpp" // IO Operation #include "CXXGraph/Graph/IO/IOUtility_impl.hpp" diff --git a/test/BipartiteTest.cpp b/test/BipartiteTest.cpp new file mode 100644 index 00000000..597d50c7 --- /dev/null +++ b/test/BipartiteTest.cpp @@ -0,0 +1,110 @@ +#include + +#include "CXXGraph/CXXGraph.hpp" +#include "gtest/gtest.h" + +// Smart pointers alias +template +using unique = std::unique_ptr; +template +using shared = std::shared_ptr; + +using std::make_shared; +using std::make_unique; + +TEST(IsBipartiteTest, bipartite_graph) { + // Bipartite graph + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 2); + CXXGraph::Node node3("3", 3); + CXXGraph::Node node4("4", 4); + + CXXGraph::UndirectedEdge edge1(1, node1, node2); + CXXGraph::UndirectedEdge edge2(2, node1, node3); + CXXGraph::UndirectedEdge edge3(3, node3, node4); + CXXGraph::UndirectedEdge edge4(4, node2, node4); + + CXXGraph::T_EdgeSet edgeSet; + edgeSet.insert(make_shared>(edge1)); + edgeSet.insert(make_shared>(edge2)); + edgeSet.insert(make_shared>(edge3)); + edgeSet.insert(make_shared>(edge4)); + + CXXGraph::Graph graph(edgeSet); + + bool isBipartite = graph.isBipartite(); + ASSERT_EQ(isBipartite, true); // This graph is bipartite +} + +TEST(IsBipartiteTest, non_bipartite_graph) { + // Non-bipartite graph with odd cycle + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 2); + CXXGraph::Node node3("3", 3); + + CXXGraph::UndirectedEdge edge1(1, node1, node2); + CXXGraph::UndirectedEdge edge2(2, node2, node3); + CXXGraph::UndirectedEdge edge3(3, node3, + node1); // Forms a cycle of 3 nodes + + CXXGraph::T_EdgeSet edgeSet; + edgeSet.insert(make_shared>(edge1)); + edgeSet.insert(make_shared>(edge2)); + edgeSet.insert(make_shared>(edge3)); + + CXXGraph::Graph graph(edgeSet); + + bool isBipartite = graph.isBipartite(); + ASSERT_EQ( + isBipartite, + false); // This graph has an odd-length cycle, so it's not bipartite +} + +TEST(IsBipartiteTest, empty_graph) { + // Empty graph + CXXGraph::T_EdgeSet edgeSet; + CXXGraph::Graph graph(edgeSet); + + bool isBipartite = graph.isBipartite(); + ASSERT_EQ(isBipartite, true); // An empty graph is trivially bipartite +} + +TEST(IsBipartiteTest, single_node_graph) { + // Single node graph (trivially bipartite) + CXXGraph::Node node1("1", 1); + CXXGraph::T_EdgeSet edgeSet; + CXXGraph::Graph graph(edgeSet); + + bool isBipartite = graph.isBipartite(); + ASSERT_EQ(isBipartite, true); // A graph with a single node is bipartite +} + +TEST(IsBipartiteTest, complex_bipartite_graph) { + // More complex bipartite graph + 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::UndirectedEdge edge1(1, node1, node2); + CXXGraph::UndirectedEdge edge2(2, node1, node3); + CXXGraph::UndirectedEdge edge3(3, node4, node5); + CXXGraph::UndirectedEdge edge4(4, node4, node6); + CXXGraph::UndirectedEdge edge5(5, node2, node4); + CXXGraph::UndirectedEdge edge6(6, node3, node5); + + 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)); + + CXXGraph::Graph graph(edgeSet); + + bool isBipartite = graph.isBipartite(); + ASSERT_EQ(isBipartite, true); // This graph is bipartite +}