Skip to content

Commit

Permalink
Welsh powell coloring (#391)
Browse files Browse the repository at this point in the history
* Wokring on getNodeSet, breaking tests

* Added welshPowellColoring algorithm, breaking 1 test in welshPowerColoringTest.cpp

* Removing assertions and <cassert>

* Transitioned from shared_ptr to node<T>, all tests passed

* Beautify code and fix comments in code

* Sync from fork
  • Loading branch information
badumbatish authored Jan 23, 2024
1 parent 87bee02 commit 3f143c9
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 0 deletions.
58 changes: 58 additions & 0 deletions include/CXXGraph/Graph/Algorithm/welshPowellColoring_impl.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// Created by jjsm on 1/22/24.
//

#ifndef CXXGRAPH_WELSHPOWELLCOLORING_IMPL_H__
#define CXXGRAPH_WELSHPOWELLCOLORING_IMPL_H__

#pragma once

#include "CXXGraph/Graph/Graph_decl.h"

namespace CXXGraph {
template <typename T>
std::map<Node<T>, int> Graph<T>::welshPowellColoring() const {
auto adjMatrix = *getAdjMatrix();
std::unordered_map<std::shared_ptr<const Node<T>>, int> degreeOfVertexMap = {};

// Find the degree of each vertex and put them in a map
for (auto &[nodeFrom, nodeToEdgeVec] : adjMatrix) {
degreeOfVertexMap[nodeFrom] = nodeToEdgeVec.size();
}

// Transform the map to the vector to sort
std::vector<std::pair<std::shared_ptr<const Node<T>>, int>> degreeOfVertexVector(degreeOfVertexMap.begin(), degreeOfVertexMap.end());

// Sort them based on the vertex degree
std::sort(degreeOfVertexVector.begin(), degreeOfVertexVector.end(), [](const auto& left, const auto& right) {
return left.second > right.second;
});

// Create a new map of coloring, where the keys are the nodes, and the value is the color order (assigned by integer)
std::map<Node<T>, int> mapOfColoring;
for (auto &[nodeFrom, _] : adjMatrix) {
mapOfColoring[*nodeFrom] = 0;
}

// Going down the list of vertex based on degrees
for (const auto& [node, _] : degreeOfVertexVector) {
// Find the smallest unused color for the current vertex
std::vector<int> usedColors(degreeOfVertexVector.size() + 1, 0);

for (const auto &[neighbor, _] : adjMatrix[node]) {
usedColors[mapOfColoring[*neighbor]] = 1;
}

// Assign the smallest unused color to the current vertex
for (int c = 1; c < usedColors.size(); c++) {
if (usedColors[c] == 0) {
mapOfColoring[*node] = c;
break;
}
}
}

return mapOfColoring;
}
}
#endif // CXXGRAPH_WELSHPOWELLCOLORING_IMPL_H__
1 change: 1 addition & 0 deletions include/CXXGraph/Graph/Graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "CXXGraph/Graph/Algorithm/Tarjan_impl.hpp"
#include "CXXGraph/Graph/Algorithm/TopologicalSort_impl.hpp"
#include "CXXGraph/Graph/Algorithm/TransitiveReduction_impl.hpp"
#include "CXXGraph/Graph/Algorithm/welshPowellColoring_impl.hpp"

// IO Operation
#include "CXXGraph/Graph/IO/IOUtility_impl.hpp"
Expand Down
11 changes: 11 additions & 0 deletions include/CXXGraph/Graph/Graph_decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,17 @@ class Graph {
virtual double fordFulkersonMaxFlow(const Node<T> &source,
const Node<T> &target) const;

/**
* @brief Welsh-Powell Coloring algorithm
* @return a std::map of keys being the nodes and the values being the color
* order (by integer) starting from 1.
* Source :
* https://www.youtube.com/watch?v=SLkyDuG1Puw&ab_channel=TheLogicalLearning
* https://www.geeksforgeeks.org/welsh-powell-graph-colouring-algorithm/
* https://www.tutorialspoint.com/de-powell-graph-colouring-algorithm
*/
virtual std::map<Node<T>, int> welshPowellColoring() const;

/**
* \brief
* This function writes the graph to an output file
Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,5 @@ if(TEST)
add_test(test_transitive_reductiono test_exe --gtest_filter=TransitiveReduction*)
add_test(test_union_find test_exe --gtest_filter=UnionFind*)
add_test(test_floyd_warshall test_exe --gtest_filter=FloydWarshall*)
add_test(test_welsh_powell_coloring test_exe --gtest_filter=welshPowellColoring*)
endif(TEST)
174 changes: 174 additions & 0 deletions test/welshPowellColoringTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#include "CXXGraph/CXXGraph.hpp"
#include "gtest/gtest.h"

TEST(welshPowellColoring, one_edge_two_nodes_undirected) {
CXXGraph::Node<int> node1("1", 1);
CXXGraph::Node<int> node2("2", 2);

CXXGraph::UndirectedWeightedEdge<int> edge12(3, node1, node2,4);

CXXGraph::T_EdgeSet<int> edgeSet;
edgeSet.insert(std::make_shared<CXXGraph::UndirectedWeightedEdge<int>>(edge12));

CXXGraph::Graph<int> graph(edgeSet);

auto result = graph.welshPowellColoring();

// get the highest coloring order
auto highest_coloring_order = std::max_element(result.begin(), result.end(),
[](const auto& lhs, const auto& rhs) {
return lhs.second < rhs.second;
}
)->second;
ASSERT_EQ(graph.isUndirectedGraph(), true);

// Asserts that the chromatic color of the graph is 2
ASSERT_EQ(highest_coloring_order, 2);
}

TEST(welshPowellColoring, undirected_simon_james) {
// https://www.youtube.com/watch?v=CQIW2mLfG04&ab_channel=SimonJames
CXXGraph::Node<int> nodeA("a", 1);
CXXGraph::Node<int> nodeB("b", 1);
CXXGraph::Node<int> nodeC("c", 1);
CXXGraph::Node<int> nodeD("d", 1);
CXXGraph::Node<int> nodeE("e", 1);
CXXGraph::Node<int> nodeF("f", 1);
CXXGraph::Node<int> nodeG("g", 1);
CXXGraph::Node<int> nodeH("h", 1);
CXXGraph::Node<int> nodeI("i", 1);
CXXGraph::Node<int> nodeJ("j", 1);
CXXGraph::Node<int> nodeK("k", 1);


CXXGraph::UndirectedEdge<int> edgeAB(1, nodeA, nodeB),
edgeBA(1, nodeB, nodeA), //

edgeAC(1, nodeA, nodeC),
edgeCA(1, nodeC, nodeA), //

edgeAD(1, nodeA, nodeD),
edgeDA(1, nodeD, nodeA), //

edgeAK(1, nodeA, nodeK),
edgeKA(1, nodeK, nodeA),

edgeAH(1, nodeA, nodeH),
edgeHA(1, nodeA, nodeH), //

edgeAE(1, nodeA, nodeE),
edgeEA(1, nodeA, nodeH), //

edgeAG(1, nodeA, nodeG),
edgeGA(1, nodeA, nodeG), //

edgeBK(1, nodeB, nodeK),
edgeKB(1, nodeK, nodeB), //

edgeBI(1, nodeB, nodeI),
edgeIB(1, nodeI, nodeB), //

edgeBJ(1, nodeB, nodeJ),
edgeJB(1, nodeJ, nodeB),

edgeBF(1, nodeB, nodeF),
edgeFB(1, nodeF, nodeB), //

edgeBD(1, nodeB, nodeD),
edgeDB(1, nodeD, nodeB), //

edgeCE(1, nodeC, nodeE),
edgeEC(1, nodeE, nodeC), //

edgeCD(1, nodeC, nodeD),
edgeDC(1, nodeD, nodeC), //

edgeCH(1, nodeC, nodeH),
edgeHC(1, nodeH, nodeC), //

edgeCG(1, nodeC, nodeG),
edgeGC(1, nodeG, nodeC), //

edgeDE(1, nodeD, nodeE),
edgeED(1, nodeD, nodeE), //

edgeEK(1, nodeE, nodeK),
edgeKE(1, nodeK, nodeE), //

edgeFI(1, nodeF, nodeI),
edgeIF(1, nodeI, nodeF),

edgeFJ(1, nodeF, nodeJ),
edgeJF(1, nodeJ, nodeF),

edgeFG(1, nodeF, nodeG),
edgeGF(1, nodeG, nodeF),

edgeGH(1, nodeG, nodeH),
edgeHG(1, nodeH, nodeG),

edgeIJ(1, nodeI, nodeJ), //
edgeJI(1, nodeJ, nodeI); //

CXXGraph::T_EdgeSet<int> edgeSet;

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeAB));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeAC));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeAD));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeAK));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeAH));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeAE));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeAG));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeBK));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeBI));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeBJ));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeBF));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeBD));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeCE));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeCD));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeCH));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeCG));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeDE));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeEK));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeFI));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeFJ));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeFG));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeGH));

edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeIJ));


CXXGraph::Graph<int> graph(edgeSet);

auto result = graph.welshPowellColoring();
auto highest_coloring_order = std::max_element(result.begin(), result.end(),
[](const auto& lhs, const auto& rhs) {
return lhs.second < rhs.second;
}
)->second;

ASSERT_EQ(graph.isUndirectedGraph(), true);
// Asserts that the chromatic color of the graph is 4, as indicated in 2:30 of video
ASSERT_EQ(highest_coloring_order, 4);
}

0 comments on commit 3f143c9

Please sign in to comment.