Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Welsh powell coloring #391

Merged
merged 7 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
Loading