Skip to content

Commit 3f143c9

Browse files
authored
Welsh powell coloring (#391)
* 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
1 parent 87bee02 commit 3f143c9

File tree

5 files changed

+245
-0
lines changed

5 files changed

+245
-0
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//
2+
// Created by jjsm on 1/22/24.
3+
//
4+
5+
#ifndef CXXGRAPH_WELSHPOWELLCOLORING_IMPL_H__
6+
#define CXXGRAPH_WELSHPOWELLCOLORING_IMPL_H__
7+
8+
#pragma once
9+
10+
#include "CXXGraph/Graph/Graph_decl.h"
11+
12+
namespace CXXGraph {
13+
template <typename T>
14+
std::map<Node<T>, int> Graph<T>::welshPowellColoring() const {
15+
auto adjMatrix = *getAdjMatrix();
16+
std::unordered_map<std::shared_ptr<const Node<T>>, int> degreeOfVertexMap = {};
17+
18+
// Find the degree of each vertex and put them in a map
19+
for (auto &[nodeFrom, nodeToEdgeVec] : adjMatrix) {
20+
degreeOfVertexMap[nodeFrom] = nodeToEdgeVec.size();
21+
}
22+
23+
// Transform the map to the vector to sort
24+
std::vector<std::pair<std::shared_ptr<const Node<T>>, int>> degreeOfVertexVector(degreeOfVertexMap.begin(), degreeOfVertexMap.end());
25+
26+
// Sort them based on the vertex degree
27+
std::sort(degreeOfVertexVector.begin(), degreeOfVertexVector.end(), [](const auto& left, const auto& right) {
28+
return left.second > right.second;
29+
});
30+
31+
// Create a new map of coloring, where the keys are the nodes, and the value is the color order (assigned by integer)
32+
std::map<Node<T>, int> mapOfColoring;
33+
for (auto &[nodeFrom, _] : adjMatrix) {
34+
mapOfColoring[*nodeFrom] = 0;
35+
}
36+
37+
// Going down the list of vertex based on degrees
38+
for (const auto& [node, _] : degreeOfVertexVector) {
39+
// Find the smallest unused color for the current vertex
40+
std::vector<int> usedColors(degreeOfVertexVector.size() + 1, 0);
41+
42+
for (const auto &[neighbor, _] : adjMatrix[node]) {
43+
usedColors[mapOfColoring[*neighbor]] = 1;
44+
}
45+
46+
// Assign the smallest unused color to the current vertex
47+
for (int c = 1; c < usedColors.size(); c++) {
48+
if (usedColors[c] == 0) {
49+
mapOfColoring[*node] = c;
50+
break;
51+
}
52+
}
53+
}
54+
55+
return mapOfColoring;
56+
}
57+
}
58+
#endif // CXXGRAPH_WELSHPOWELLCOLORING_IMPL_H__

include/CXXGraph/Graph/Graph.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "CXXGraph/Graph/Algorithm/Tarjan_impl.hpp"
4242
#include "CXXGraph/Graph/Algorithm/TopologicalSort_impl.hpp"
4343
#include "CXXGraph/Graph/Algorithm/TransitiveReduction_impl.hpp"
44+
#include "CXXGraph/Graph/Algorithm/welshPowellColoring_impl.hpp"
4445

4546
// IO Operation
4647
#include "CXXGraph/Graph/IO/IOUtility_impl.hpp"

include/CXXGraph/Graph/Graph_decl.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,17 @@ class Graph {
795795
virtual double fordFulkersonMaxFlow(const Node<T> &source,
796796
const Node<T> &target) const;
797797

798+
/**
799+
* @brief Welsh-Powell Coloring algorithm
800+
* @return a std::map of keys being the nodes and the values being the color
801+
* order (by integer) starting from 1.
802+
* Source :
803+
* https://www.youtube.com/watch?v=SLkyDuG1Puw&ab_channel=TheLogicalLearning
804+
* https://www.geeksforgeeks.org/welsh-powell-graph-colouring-algorithm/
805+
* https://www.tutorialspoint.com/de-powell-graph-colouring-algorithm
806+
*/
807+
virtual std::map<Node<T>, int> welshPowellColoring() const;
808+
798809
/**
799810
* \brief
800811
* This function writes the graph to an output file

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,5 @@ if(TEST)
9898
add_test(test_transitive_reductiono test_exe --gtest_filter=TransitiveReduction*)
9999
add_test(test_union_find test_exe --gtest_filter=UnionFind*)
100100
add_test(test_floyd_warshall test_exe --gtest_filter=FloydWarshall*)
101+
add_test(test_welsh_powell_coloring test_exe --gtest_filter=welshPowellColoring*)
101102
endif(TEST)

test/welshPowellColoringTest.cpp

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
#include "CXXGraph/CXXGraph.hpp"
2+
#include "gtest/gtest.h"
3+
4+
TEST(welshPowellColoring, one_edge_two_nodes_undirected) {
5+
CXXGraph::Node<int> node1("1", 1);
6+
CXXGraph::Node<int> node2("2", 2);
7+
8+
CXXGraph::UndirectedWeightedEdge<int> edge12(3, node1, node2,4);
9+
10+
CXXGraph::T_EdgeSet<int> edgeSet;
11+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedWeightedEdge<int>>(edge12));
12+
13+
CXXGraph::Graph<int> graph(edgeSet);
14+
15+
auto result = graph.welshPowellColoring();
16+
17+
// get the highest coloring order
18+
auto highest_coloring_order = std::max_element(result.begin(), result.end(),
19+
[](const auto& lhs, const auto& rhs) {
20+
return lhs.second < rhs.second;
21+
}
22+
)->second;
23+
ASSERT_EQ(graph.isUndirectedGraph(), true);
24+
25+
// Asserts that the chromatic color of the graph is 2
26+
ASSERT_EQ(highest_coloring_order, 2);
27+
}
28+
29+
TEST(welshPowellColoring, undirected_simon_james) {
30+
// https://www.youtube.com/watch?v=CQIW2mLfG04&ab_channel=SimonJames
31+
CXXGraph::Node<int> nodeA("a", 1);
32+
CXXGraph::Node<int> nodeB("b", 1);
33+
CXXGraph::Node<int> nodeC("c", 1);
34+
CXXGraph::Node<int> nodeD("d", 1);
35+
CXXGraph::Node<int> nodeE("e", 1);
36+
CXXGraph::Node<int> nodeF("f", 1);
37+
CXXGraph::Node<int> nodeG("g", 1);
38+
CXXGraph::Node<int> nodeH("h", 1);
39+
CXXGraph::Node<int> nodeI("i", 1);
40+
CXXGraph::Node<int> nodeJ("j", 1);
41+
CXXGraph::Node<int> nodeK("k", 1);
42+
43+
44+
CXXGraph::UndirectedEdge<int> edgeAB(1, nodeA, nodeB),
45+
edgeBA(1, nodeB, nodeA), //
46+
47+
edgeAC(1, nodeA, nodeC),
48+
edgeCA(1, nodeC, nodeA), //
49+
50+
edgeAD(1, nodeA, nodeD),
51+
edgeDA(1, nodeD, nodeA), //
52+
53+
edgeAK(1, nodeA, nodeK),
54+
edgeKA(1, nodeK, nodeA),
55+
56+
edgeAH(1, nodeA, nodeH),
57+
edgeHA(1, nodeA, nodeH), //
58+
59+
edgeAE(1, nodeA, nodeE),
60+
edgeEA(1, nodeA, nodeH), //
61+
62+
edgeAG(1, nodeA, nodeG),
63+
edgeGA(1, nodeA, nodeG), //
64+
65+
edgeBK(1, nodeB, nodeK),
66+
edgeKB(1, nodeK, nodeB), //
67+
68+
edgeBI(1, nodeB, nodeI),
69+
edgeIB(1, nodeI, nodeB), //
70+
71+
edgeBJ(1, nodeB, nodeJ),
72+
edgeJB(1, nodeJ, nodeB),
73+
74+
edgeBF(1, nodeB, nodeF),
75+
edgeFB(1, nodeF, nodeB), //
76+
77+
edgeBD(1, nodeB, nodeD),
78+
edgeDB(1, nodeD, nodeB), //
79+
80+
edgeCE(1, nodeC, nodeE),
81+
edgeEC(1, nodeE, nodeC), //
82+
83+
edgeCD(1, nodeC, nodeD),
84+
edgeDC(1, nodeD, nodeC), //
85+
86+
edgeCH(1, nodeC, nodeH),
87+
edgeHC(1, nodeH, nodeC), //
88+
89+
edgeCG(1, nodeC, nodeG),
90+
edgeGC(1, nodeG, nodeC), //
91+
92+
edgeDE(1, nodeD, nodeE),
93+
edgeED(1, nodeD, nodeE), //
94+
95+
edgeEK(1, nodeE, nodeK),
96+
edgeKE(1, nodeK, nodeE), //
97+
98+
edgeFI(1, nodeF, nodeI),
99+
edgeIF(1, nodeI, nodeF),
100+
101+
edgeFJ(1, nodeF, nodeJ),
102+
edgeJF(1, nodeJ, nodeF),
103+
104+
edgeFG(1, nodeF, nodeG),
105+
edgeGF(1, nodeG, nodeF),
106+
107+
edgeGH(1, nodeG, nodeH),
108+
edgeHG(1, nodeH, nodeG),
109+
110+
edgeIJ(1, nodeI, nodeJ), //
111+
edgeJI(1, nodeJ, nodeI); //
112+
113+
CXXGraph::T_EdgeSet<int> edgeSet;
114+
115+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeAB));
116+
117+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeAC));
118+
119+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeAD));
120+
121+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeAK));
122+
123+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeAH));
124+
125+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeAE));
126+
127+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeAG));
128+
129+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeBK));
130+
131+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeBI));
132+
133+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeBJ));
134+
135+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeBF));
136+
137+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeBD));
138+
139+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeCE));
140+
141+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeCD));
142+
143+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeCH));
144+
145+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeCG));
146+
147+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeDE));
148+
149+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeEK));
150+
151+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeFI));
152+
153+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeFJ));
154+
155+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeFG));
156+
157+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeGH));
158+
159+
edgeSet.insert(std::make_shared<CXXGraph::UndirectedEdge<int>>(edgeIJ));
160+
161+
162+
CXXGraph::Graph<int> graph(edgeSet);
163+
164+
auto result = graph.welshPowellColoring();
165+
auto highest_coloring_order = std::max_element(result.begin(), result.end(),
166+
[](const auto& lhs, const auto& rhs) {
167+
return lhs.second < rhs.second;
168+
}
169+
)->second;
170+
171+
ASSERT_EQ(graph.isUndirectedGraph(), true);
172+
// Asserts that the chromatic color of the graph is 4, as indicated in 2:30 of video
173+
ASSERT_EQ(highest_coloring_order, 4);
174+
}

0 commit comments

Comments
 (0)