Graph colouring: Difference between revisions

(→‎{{header|zkl}}: added code)
 
(26 intermediate revisions by 14 users not shown)
Line 147:
* [[wp:Greedy coloring|Greedy coloring]] Wikipedia.
* [https://www.slideshare.net/PriyankJain26/graph-coloring-48222920 Graph Coloring : Greedy Algorithm & Welsh Powell Algorithm] by Priyank Jain.
 
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">F first_avail_int(data)
‘return lowest int 0... not in data’
V d = Set(data)
L(i) 0..
I i !C d
R i
 
F greedy_colour(name, connections)
DefaultDict[Int, [Int]] graph
 
L(connection) connections.split(‘ ’)
I ‘-’ C connection
V (n1, n2) = connection.split(‘-’).map(Int)
graph[n1].append(n2)
graph[n2].append(n1)
E
graph[Int(connection)] = [Int]()
 
// Greedy colourisation algo
V order = sorted(graph.keys())
[Int = Int] colour
V neighbours = graph
L(node) order
V used_neighbour_colours = neighbours[node].filter(nbr -> nbr C @colour).map(nbr -> @colour[nbr])
colour[node] = first_avail_int(used_neighbour_colours)
 
print("\n"name)
V canonical_edges = Set[(Int, Int)]()
L(n1, neighbours) sorted(graph.items())
I !neighbours.empty
L(n2) neighbours
V edge = tuple_sorted((n1, n2))
I edge !C canonical_edges
print(‘ #.-#.: Colour: #., #.’.format(n1, n2, colour[n1], colour[n2]))
canonical_edges.add(edge)
E
print(‘ #.: Colour: #.’.format(n1, colour[n1]))
V lc = Set(colour.values()).len
print(" #Nodes: #.\n #Edges: #.\n #Colours: #.".format(colour.len, canonical_edges.len, lc))
 
L(name, connections) [
(‘Ex1’, ‘0-1 1-2 2-0 3’),
(‘Ex2’, ‘1-6 1-7 1-8 2-5 2-7 2-8 3-5 3-6 3-8 4-5 4-6 4-7’),
(‘Ex3’, ‘1-4 1-6 1-8 3-2 3-6 3-8 5-2 5-4 5-8 7-2 7-4 7-6’),
(‘Ex4’, ‘1-6 7-1 8-1 5-2 2-7 2-8 3-5 6-3 3-8 4-5 4-6 4-7’)]
greedy_colour(name, connections)</syntaxhighlight>
 
{{out}}
<pre>
 
Ex1
0-1: Colour: 0, 1
0-2: Colour: 0, 2
1-2: Colour: 1, 2
3: Colour: 0
#Nodes: 4
#Edges: 3
#Colours: 3
 
Ex2
1-6: Colour: 0, 1
1-7: Colour: 0, 1
1-8: Colour: 0, 1
2-5: Colour: 0, 1
2-7: Colour: 0, 1
2-8: Colour: 0, 1
3-5: Colour: 0, 1
3-6: Colour: 0, 1
3-8: Colour: 0, 1
4-5: Colour: 0, 1
4-6: Colour: 0, 1
4-7: Colour: 0, 1
#Nodes: 8
#Edges: 12
#Colours: 2
 
Ex3
1-4: Colour: 0, 1
1-6: Colour: 0, 2
1-8: Colour: 0, 3
2-3: Colour: 0, 1
2-5: Colour: 0, 2
2-7: Colour: 0, 3
3-6: Colour: 1, 2
3-8: Colour: 1, 3
4-5: Colour: 1, 2
4-7: Colour: 1, 3
5-8: Colour: 2, 3
6-7: Colour: 2, 3
#Nodes: 8
#Edges: 12
#Colours: 4
 
Ex4
1-6: Colour: 0, 1
1-7: Colour: 0, 1
1-8: Colour: 0, 1
2-5: Colour: 0, 1
2-7: Colour: 0, 1
2-8: Colour: 0, 1
3-5: Colour: 0, 1
3-6: Colour: 0, 1
3-8: Colour: 0, 1
4-5: Colour: 0, 1
4-6: Colour: 0, 1
4-7: Colour: 0, 1
#Nodes: 8
#Edges: 12
#Colours: 2
</pre>
 
=={{header|C#}}==
{{trans|Java}}
<syntaxhighlight lang="C#">
using System;
using System.Collections.Generic;
using System.Linq;
 
public static class GraphColoring
{
public static void Main(string[] args)
{
Colorize("0-1 1-2 2-0 3");
Colorize("1-6 1-7 1-8 2-5 2-7 2-8 3-5 3-6 3-8 4-5 4-6 4-7");
Colorize("1-4 1-6 1-8 3-2 3-6 3-8 5-2 5-4 5-8 7-2 7-4 7-6");
Colorize("1-6 7-1 8-1 5-2 2-7 2-8 3-5 6-3 3-8 4-5 4-6 4-7");
}
 
private static void Colorize(string graphRepresentation)
{
List<Node> graph = InitializeGraph(graphRepresentation);
List<Node> nodes = new List<Node>(graph);
while (nodes.Any())
{
Node maxNode = nodes.OrderByDescending(n => n.Saturation).First();
maxNode.Color = MinColor(maxNode);
UpdateSaturation(maxNode, nodes);
nodes.Remove(maxNode);
}
 
Console.WriteLine("Graph: " + graphRepresentation);
Display(graph);
}
 
private static Color MinColor(Node node)
{
HashSet<Color> colorsUsed = ColorsUsed(node);
foreach (Color color in Enum.GetValues(typeof(Color)))
{
if (!colorsUsed.Contains(color))
{
return color;
}
}
return Color.NoColor;
}
 
private static HashSet<Color> ColorsUsed(Node node)
{
return new HashSet<Color>(node.Neighbours.Select(n => n.Color));
}
 
private static void UpdateSaturation(Node node, List<Node> nodes)
{
foreach (Node neighbour in node.Neighbours)
{
if (neighbour.Color == Color.NoColor)
{
neighbour.Saturation = ColorsUsed(neighbour).Count;
}
}
}
 
private static void Display(List<Node> nodes)
{
HashSet<Color> graphColors = new HashSet<Color>(nodes.Select(n => n.Color));
foreach (Node node in nodes)
{
Console.Write($"Node {node.Index}: color = {node.Color}");
if (node.Neighbours.Any())
{
var indexes = node.Neighbours.Select(n => n.Index).ToList();
Console.Write(new string(' ', 8 - node.Color.ToString().Length) + "neighbours = " + string.Join(", ", indexes));
}
Console.WriteLine();
}
 
Console.WriteLine("Number of colours used: " + graphColors.Count);
Console.WriteLine();
}
 
private static List<Node> InitializeGraph(string graphRepresentation)
{
SortedDictionary<int, Node> map = new SortedDictionary<int, Node>();
foreach (string element in graphRepresentation.Split(' '))
{
if (element.Contains("-"))
{
string[] parts = element.Split('-');
int index1 = int.Parse(parts[0]);
int index2 = int.Parse(parts[1]);
Node node1 = map.GetOrAdd(index1, () => new Node(index1));
Node node2 = map.GetOrAdd(index2, () => new Node(index2));
node1.Neighbours.Add(node2);
node2.Neighbours.Add(node1);
}
else
{
int index = int.Parse(element);
map.GetOrAdd(index, () => new Node(index));
}
}
 
return new List<Node>(map.Values);
}
 
public enum Color { Blue, Green, Red, Yellow, Cyan, Orange, NoColor }
 
public class Node
{
public Node(int index)
{
Index = index;
Color = Color.NoColor;
Neighbours = new HashSet<Node>();
}
 
public int Index { get; }
public int Saturation { get; set; }
public Color Color { get; set; }
public HashSet<Node> Neighbours { get; }
}
 
private static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, Func<TValue> valueFactory)
{
if (!dictionary.TryGetValue(key, out TValue value))
{
value = valueFactory();
dictionary[key] = value;
}
return value;
}
}
</syntaxhighlight>
{{out}}
<pre>
Graph: 0-1 1-2 2-0 3
Node 0: color = Blue neighbours = 1, 2
Node 1: color = Green neighbours = 0, 2
Node 2: color = Red neighbours = 1, 0
Node 3: color = Blue
Number of colours used: 3
 
Graph: 1-6 1-7 1-8 2-5 2-7 2-8 3-5 3-6 3-8 4-5 4-6 4-7
Node 1: color = Blue neighbours = 6, 7, 8
Node 2: color = Blue neighbours = 5, 7, 8
Node 3: color = Blue neighbours = 5, 6, 8
Node 4: color = Blue neighbours = 5, 6, 7
Node 5: color = Green neighbours = 2, 3, 4
Node 6: color = Green neighbours = 1, 3, 4
Node 7: color = Green neighbours = 1, 2, 4
Node 8: color = Green neighbours = 1, 2, 3
Number of colours used: 2
 
Graph: 1-4 1-6 1-8 3-2 3-6 3-8 5-2 5-4 5-8 7-2 7-4 7-6
Node 1: color = Blue neighbours = 4, 6, 8
Node 2: color = Green neighbours = 3, 5, 7
Node 3: color = Blue neighbours = 2, 6, 8
Node 4: color = Green neighbours = 1, 5, 7
Node 5: color = Blue neighbours = 2, 4, 8
Node 6: color = Green neighbours = 1, 3, 7
Node 7: color = Blue neighbours = 2, 4, 6
Node 8: color = Green neighbours = 1, 3, 5
Number of colours used: 2
 
Graph: 1-6 7-1 8-1 5-2 2-7 2-8 3-5 6-3 3-8 4-5 4-6 4-7
Node 1: color = Blue neighbours = 6, 7, 8
Node 2: color = Blue neighbours = 5, 7, 8
Node 3: color = Blue neighbours = 5, 6, 8
Node 4: color = Blue neighbours = 5, 6, 7
Node 5: color = Green neighbours = 2, 3, 4
Node 6: color = Green neighbours = 1, 3, 4
Node 7: color = Green neighbours = 1, 2, 4
Node 8: color = Green neighbours = 1, 2, 3
Number of colours used: 2
 
 
</pre>
 
=={{header|C++}}==
Using the DSatur algorithm from https://en.wikipedia.org/wiki/DSatur
<syntaxhighlight lang="c++">
#include <algorithm>
#include <cstdint>
#include <iostream>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <unordered_set>
#include <vector>
 
const std::vector<std::string> all_colours = { "PINK", "ORANGE", "CYAN", "YELLOW", "RED", "GREEN", "BLUE" };
 
class Node {
public:
Node(const int32_t& aID, const int32_t& aSaturation, const std::string& aColour)
: id(aID), saturation(aSaturation), colour(aColour) {}
 
Node() : id(0), saturation(0), colour("NO_COLOUR") {}
 
int32_t id, saturation;
std::string colour;
bool excluded_from_search = false;
};
 
int main() {
std::map<int32_t, Node, decltype([](const int32_t& a, const int32_t& b){ return a < b; })> graph;
 
std::map<int32_t, std::set<int32_t, decltype([](const int32_t& a, const int32_t& b) { return a < b; })>,
decltype([](const int32_t& a, const int32_t& b) { return a < b; })> neighbours;
 
const std::vector<std::string> graph_representations = { "0-1 1-2 2-0 3",
"1-6 1-7 1-8 2-5 2-7 2-8 3-5 3-6 3-8 4-5 4-6 4-7",
"1-4 1-6 1-8 3-2 3-6 3-8 5-2 5-4 5-8 7-2 7-4 7-6",
"1-6 7-1 8-1 5-2 2-7 2-8 3-5 6-3 3-8 4-5 4-6 4-7" };
 
for ( const std::string& graph_representation : graph_representations ) {
graph.clear();
neighbours.clear();
std::stringstream stream(graph_representation);
std::string element;
while ( stream >> element ) {
if ( element.find("-") != std::string::npos ) {
const int32_t id1 = element[0] - '0';
const int32_t id2 = element[element.length() - 1] - '0';
 
if ( ! graph.contains(id1) ) {
graph[id1] = Node(id1, 0, "NO_COLOUR");
}
Node node1 = graph[id1];
 
if ( ! graph.contains(id2) ) {
graph[id2] = Node(id2, 0, "NO_COLOUR");
}
Node node2 = graph[id2];
 
neighbours[id1].emplace(id2);
neighbours[id2].emplace(id1);
} else {
const int32_t id = element[0] - '0';
if ( ! graph.contains(id) ) {
graph[id] = Node(id, 0, "NO_COLOUR");
}
}
}
 
for ( uint64_t i = 0; i < graph.size(); ++i ) {
int32_t max_node_id = -1;
int32_t max_saturation = -1;
for ( const auto& [key, value] : graph ) {
if ( ! value.excluded_from_search && value.saturation > max_saturation ) {
max_saturation = value.saturation;
max_node_id = key;
}
}
 
std::unordered_set<std::string> colours_used;
for ( const int32_t& neighbour : neighbours[max_node_id] ) {
colours_used.emplace(graph[neighbour].colour);
}
 
std::string min_colour;
for ( const std::string& colour : all_colours ) {
if ( ! colours_used.contains(colour) ) {
min_colour = colour;
}
}
 
graph[max_node_id].excluded_from_search = true;
graph[max_node_id].colour = min_colour;
 
for ( int32_t neighbour : neighbours[max_node_id] ) {
if ( graph[neighbour].colour == "NO_COLOUR" ) {
graph[neighbour].saturation = colours_used.size();
}
}
}
 
std::unordered_set<std::string> graph_colours;
for ( const auto& [key, value] : graph ) {
graph_colours.emplace(value.colour);
std::cout << "Node " << key << ": colour = " + value.colour;
 
if ( ! neighbours[key].empty() ) {
std::cout << std::string(8 - value.colour.length(), ' ') << "neighbours = ";
for ( const int32_t& neighbour : neighbours[key] ) {
std::cout << neighbour << " ";
}
}
std::cout << std::endl;
}
std::cout << "Number of colours used: " << graph_colours.size() << std::endl << std::endl;
}
}
</syntaxhighlight>
{{ out }}
<pre>
Node 0: colour = BLUE neighbours = 1 2
Node 1: colour = GREEN neighbours = 0 2
Node 2: colour = RED neighbours = 0 1
Node 3: colour = BLUE
Number of colours used: 3
 
Node 1: colour = BLUE neighbours = 6 7 8
Node 2: colour = BLUE neighbours = 5 7 8
Node 3: colour = BLUE neighbours = 5 6 8
Node 4: colour = BLUE neighbours = 5 6 7
Node 5: colour = GREEN neighbours = 2 3 4
Node 6: colour = GREEN neighbours = 1 3 4
Node 7: colour = GREEN neighbours = 1 2 4
Node 8: colour = GREEN neighbours = 1 2 3
Number of colours used: 2
 
Node 1: colour = BLUE neighbours = 4 6 8
Node 2: colour = GREEN neighbours = 3 5 7
Node 3: colour = BLUE neighbours = 2 6 8
Node 4: colour = GREEN neighbours = 1 5 7
Node 5: colour = BLUE neighbours = 2 4 8
Node 6: colour = GREEN neighbours = 1 3 7
Node 7: colour = BLUE neighbours = 2 4 6
Node 8: colour = GREEN neighbours = 1 3 5
Number of colours used: 2
 
Node 1: colour = BLUE neighbours = 6 7 8
Node 2: colour = BLUE neighbours = 5 7 8
Node 3: colour = BLUE neighbours = 5 6 8
Node 4: colour = BLUE neighbours = 5 6 7
Node 5: colour = GREEN neighbours = 2 3 4
Node 6: colour = GREEN neighbours = 1 3 4
Node 7: colour = GREEN neighbours = 1 2 4
Node 8: colour = GREEN neighbours = 1 2 3
Number of colours used: 2
</pre>
 
=={{header|Go}}==
Line 154 ⟶ 603:
 
The results agree with the Python entry for examples 1 and 2 but, for example 3, Python gives 2 colors compared to my 4 and, for example 4, Python gives 3 colors compared to my 2.
<langsyntaxhighlight lang="go">package main
 
import (
Line 325 ⟶ 774:
}
}
}</langsyntaxhighlight>
 
{{out}}
Line 453 ⟶ 902:
Number of colors : 2
</pre>
 
=={{header|Haskell}}==
 
<syntaxhighlight lang="haskell">import Data.Maybe
import Data.List
import Control.Monad.State
import qualified Data.Map as M
import Text.Printf
 
------------------------------------------------------------
-- Primitive graph representation
 
type Node = Int
type Color = Int
type Graph = M.Map Node [Node]
 
nodes :: Graph -> [Node]
nodes = M.keys
 
adjacentNodes :: Graph -> Node -> [Node]
adjacentNodes g n = fromMaybe [] $ M.lookup n g
 
degree :: Graph -> Node -> Int
degree g = length . adjacentNodes g
 
fromList :: [(Node, [Node])] -> Graph
fromList = foldr add M.empty
where
add (a, bs) g = foldr (join [a]) (join bs a g) bs
join = flip (M.insertWith (++))
 
readGraph :: String -> Graph
readGraph = fromList . map interprete . words
where
interprete s = case span (/= '-') s of
(a, "") -> (read a, [])
(a, '-':b) -> (read a, [read b])
 
------------------------------------------------------------
-- Graph coloring functions
 
uncolored :: Node -> State [(Node, Color)] Bool
uncolored n = isNothing <$> colorOf n
 
colorOf :: Node -> State [(Node, Color)] (Maybe Color)
colorOf n = gets (lookup n)
 
greedyColoring :: Graph -> [(Node, Color)]
greedyColoring g = mapM_ go (nodes g) `execState` []
where
go n = do
c <- colorOf n
when (isNothing c) $ do
adjacentColors <- nub . catMaybes <$> mapM colorOf (adjacentNodes g n)
let newColor = head $ filter (`notElem` adjacentColors) [1..]
modify ((n, newColor) :)
filterM uncolored (adjacentNodes g n) >>= mapM_ go
 
wpColoring :: Graph -> [(Node, Color)]
wpColoring g = go [1..] nodesList `execState` []
where
nodesList = sortOn (negate . degree g) (nodes g)
 
go _ [] = pure ()
go (c:cs) ns = do
mark c ns
filterM uncolored ns >>= go cs
 
mark c [] = pure () :: State [(Node, Color)] ()
mark c (n:ns) = do
modify ((n, c) :)
mark c (filter (`notElem` adjacentNodes g n) ns)</syntaxhighlight>
 
Simple usage examples:
 
<pre>λ> let g = fromList [(1,[2,3]),(2,[3,4]),(4,[3,5])]
 
λ> g
fromList [(1,[2,3]),(2,[1,3,4]),(3,[1,2,4]),(4,[2,3,5]),(5,[4])]
 
λ> greedyColoring g
[(5,2),(4,1),(3,3),(2,2),(1,1)]
 
λ> wpColoring g
[(1,3),(4,3),(3,2),(5,1),(2,1)]</pre>
 
The task:
<syntaxhighlight lang="haskell">ex1 = "0-1 1-2 2-0 3"
ex2 = "1-6 1-7 1-8 2-5 2-7 2-8 3-5 3-6 3-8 4-5 4-6 4-7"
ex3 = "1-4 1-6 1-8 3-2 3-6 3-8 5-2 5-4 5-8 7-2 7-4 7-6"
ex4 = "1-6 7-1 8-1 5-2 2-7 2-8 3-5 6-3 3-8 4-5 4-6 4-7"
 
task method ex =
let g = readGraph ex
cs = sortOn fst $ method g
color n = fromJust $ lookup n cs
ns = nodes g
mkLine n = printf "%d\t%d\t%s\n" n (color n) (show (color <$> adjacentNodes g n))
in do
print ex
putStrLn $ "nodes:\t" ++ show ns
putStrLn $ "colors:\t" ++ show (nub (snd <$> cs))
putStrLn "node\tcolor\tadjacent colors"
mapM_ mkLine ns
putStrLn ""</syntaxhighlight>
 
Runing greedy algorithm:
<pre>λ> mapM_ (task greedyColoring) [ex1,ex2,ex3,ex4]
"0-1 1-2 2-0 3"
nodes: [0,1,2,3]
colors: [1,2,3]
node color adjacent colors
0 1 [2,3]
1 2 [1,3]
2 3 [2,1]
3 1 []
 
"1-6 1-7 1-8 2-5 2-7 2-8 3-5 3-6 3-8 4-5 4-6 4-7"
nodes: [1,2,3,4,5,6,7,8]
colors: [1,2]
node color adjacent colors
1 1 [2,2,2]
2 1 [2,2,2]
3 1 [2,2,2]
4 1 [2,2,2]
5 2 [1,1,1]
6 2 [1,1,1]
7 2 [1,1,1]
8 2 [1,1,1]
 
"1-4 1-6 1-8 3-2 3-6 3-8 5-2 5-4 5-8 7-2 7-4 7-6"
nodes: [1,2,3,4,5,6,7,8]
colors: [1,2]
node color adjacent colors
1 1 [2,2,2]
2 2 [1,1,1]
3 1 [2,2,2]
4 2 [1,1,1]
5 1 [2,2,2]
6 2 [1,1,1]
7 1 [2,2,2]
8 2 [1,1,1]
 
"1-6 7-1 8-1 5-2 2-7 2-8 3-5 6-3 3-8 4-5 4-6 4-7"
nodes: [1,2,3,4,5,6,7,8]
colors: [1,2]
node color adjacent colors
1 1 [2,2,2]
2 1 [2,2,2]
3 1 [2,2,2]
4 1 [2,2,2]
5 2 [1,1,1]
6 2 [1,1,1]
7 2 [1,1,1]
8 2 [1,1,1] </pre>
 
Runing Welsh-Powell algorithm:
 
<pre>λ> mapM_ (task wpColoring) [ex1,ex2,ex3,ex4]
"0-1 1-2 2-0 3"
nodes: [0,1,2,3]
colors: [1,2,3]
node color adjacent colors
0 1 [2,3]
1 2 [1,3]
2 3 [2,1]
3 1 []
 
"1-6 1-7 1-8 2-5 2-7 2-8 3-5 3-6 3-8 4-5 4-6 4-7"
nodes: [1,2,3,4,5,6,7,8]
colors: [1,2]
node color adjacent colors
1 1 [2,2,2]
2 1 [2,2,2]
3 1 [2,2,2]
4 1 [2,2,2]
5 2 [1,1,1]
6 2 [1,1,1]
7 2 [1,1,1]
8 2 [1,1,1]
 
"1-4 1-6 1-8 3-2 3-6 3-8 5-2 5-4 5-8 7-2 7-4 7-6"
nodes: [1,2,3,4,5,6,7,8]
colors: [1,2,3,4]
node color adjacent colors
1 1 [2,3,4]
2 1 [2,3,4]
3 2 [1,3,4]
4 2 [1,3,4]
5 3 [1,2,4]
6 3 [1,2,4]
7 4 [1,2,3]
8 4 [1,2,3]
 
"1-6 7-1 8-1 5-2 2-7 2-8 3-5 6-3 3-8 4-5 4-6 4-7"
nodes: [1,2,3,4,5,6,7,8]
colors: [1,2]
node color adjacent colors
1 1 [2,2,2]
2 1 [2,2,2]
3 1 [2,2,2]
4 1 [2,2,2]
5 2 [1,1,1]
6 2 [1,1,1]
7 2 [1,1,1]
8 2 [1,1,1]</pre>
 
=={{header|J}}==
Greedy coloring satisfies the task requirements.
<syntaxhighlight lang="j">parse=: {{
ref=: 2$L:1(;:each cut y) -.L:1 ;:'-'
labels=: /:~~.;ref
sparse=. (*:#labels) > 20*#ref
graph=: (+.|:) 1 (labels i.L:1 ref)} $.^:sparse 0$~2##labels
}}
 
greedy=: {{
colors=. (#y)#a:
for_node.y do.
color=. <{.(-.~ [:i.1+#) ~.;node#colors
colors=. color node_index} colors
end.
;colors
}}</syntaxhighlight>
 
To display colors for edges, we show the graph specification and beneath the representation of each edge A-B we show colorA:colorB.
 
<syntaxhighlight lang="j">
ex1=:'0-1 1-2 2-0 3'
ex2=:'1-6 1-7 1-8 2-5 2-7 2-8 3-5 3-6 3-8 4-5 4-6 4-7'
ex3=:'1-4 1-6 1-8 3-2 3-6 3-8 5-2 5-4 5-8 7-2 7-4 7-6'
ex4=:'1-6 7-1 8-1 5-2 2-7 2-8 3-5 6-3 3-8 4-5 4-6 4-7'
require'format/printf'
require'format/printf'
task=: {{
colors=. greedy parse y
echo'nodes: %d, edges: %d, colours: %d' sprintf #each graph;ref;~.colors
edgecolors=. <@(,&":':',&":])/"1(>labels i.L:1 ref){colors
,./>' ',.~each^:2(cut y),:each edgecolors
}}
 
task ex1
nodes: 4, edges: 4, colours: 3
0-1 1-2 2-0 3
0:1 1:2 2:0 0:0
task ex2
nodes: 8, edges: 12, colours: 2
1-6 1-7 1-8 2-5 2-7 2-8 3-5 3-6 3-8 4-5 4-6 4-7
0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1
task ex3
nodes: 8, edges: 12, colours: 4
1-4 1-6 1-8 3-2 3-6 3-8 5-2 5-4 5-8 7-2 7-4 7-6
0:1 0:2 0:3 1:0 1:2 1:3 2:0 2:1 2:3 3:0 3:1 3:2
task ex4
nodes: 8, edges: 12, colours: 2
1-6 7-1 8-1 5-2 2-7 2-8 3-5 6-3 3-8 4-5 4-6 4-7
0:1 1:0 1:0 1:0 0:1 0:1 0:1 1:0 0:1 0:1 0:1 0:1
</syntaxhighlight>
 
But, of course, we can do better than that. For example, we can try a few random ordered greedy color assignments, retaining a color assignment with the fewest colors:
 
<syntaxhighlight lang="j">anneal=: {{
best=. i.#y [ cost=. #~.greedy y
for.i.#y do.
o=. ?~#y
c=.#~.greedy o ([ { {"1) y
if. cost > c do.
best=. o [ cost=. c
end.
end.
(/:best) { greedy best ([ { {"1) y
}}
task=: {{
colors=. anneal parse y
echo'nodes: %d, edges: %d, colours: %d' sprintf #each graph;ref;~.colors
edgecolors=. <@(,&":':',&":])/"1(>labels i.L:1 ref){colors
,./>' ',.~each^:2(cut y),:each edgecolors
}}
 
task ex1
nodes: 4, edges: 4, colours: 3
0-1 1-2 2-0 3
0:1 1:2 2:0 0:0
task ex2
nodes: 8, edges: 12, colours: 2
1-6 1-7 1-8 2-5 2-7 2-8 3-5 3-6 3-8 4-5 4-6 4-7
0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1
task ex3
nodes: 8, edges: 12, colours: 2
1-4 1-6 1-8 3-2 3-6 3-8 5-2 5-4 5-8 7-2 7-4 7-6
0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1
task ex4
nodes: 8, edges: 12, colours: 2
1-6 7-1 8-1 5-2 2-7 2-8 3-5 6-3 3-8 4-5 4-6 4-7
0:1 1:0 1:0 1:0 0:1 0:1 0:1 1:0 0:1 0:1 0:1 0:1
</syntaxhighlight>
 
=={{header|Java}}==
Using the DSatur algorithm from https://en.wikipedia.org/wiki/DSatur
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
 
public final class GraphColoring {
 
public static void main(String[] aArgs) {
colourise("0-1 1-2 2-0 3");
colourise("1-6 1-7 1-8 2-5 2-7 2-8 3-5 3-6 3-8 4-5 4-6 4-7");
colourise("1-4 1-6 1-8 3-2 3-6 3-8 5-2 5-4 5-8 7-2 7-4 7-6");
colourise("1-6 7-1 8-1 5-2 2-7 2-8 3-5 6-3 3-8 4-5 4-6 4-7");
}
private static void colourise(String aGraphRepresentation) {
List<Node> graph = initialiseGraph(aGraphRepresentation);
List<Node> nodes = new ArrayList<Node>(graph);
while ( ! nodes.isEmpty() ) {
Node maxNode = nodes.stream().max( (one, two) -> Integer.compare(one.saturation, two.saturation) ).get();
maxNode.colour = minColour(maxNode);
updateSaturation(maxNode);
nodes.remove(maxNode);
}
System.out.println("Graph: " + aGraphRepresentation);
display(graph);
}
private static Colour minColour(Node aNode) {
Set<Colour> coloursUsed = coloursUsed(aNode);
for ( Colour colour : Colour.values() ) {
if ( ! coloursUsed.contains(colour) ) {
return colour;
}
}
return Colour.NO_COLOUR;
}
private static Set<Colour> coloursUsed(Node aNode) {
Set<Colour> coloursUsed = new HashSet<Colour>();
for ( Node neighbour : aNode.neighbours ) {
coloursUsed.add(neighbour.colour);
}
return coloursUsed;
}
private static void updateSaturation(Node aNode) {
for ( Node neighbour : aNode.neighbours ) {
if ( neighbour.colour == Colour.NO_COLOUR ) {
neighbour.saturation = coloursUsed(aNode).size();
}
}
}
private static void display(List<Node> aNodes) {
Set<Colour> graphColours = new HashSet<Colour>();
for ( Node node : aNodes ) {
graphColours.add(node.colour);
System.out.print("Node " + node.index + ": colour = " + node.colour);
if ( ! node.neighbours.isEmpty() ) {
List<Integer> indexes = node.neighbours.stream().map( n -> n.index ).toList();
System.out.print(" ".repeat(8 - String.valueOf(node.colour).length()) + "neighbours = " + indexes);
}
System.out.println();
}
System.out.println("Number of colours used: " + graphColours.size());
System.out.println();
}
private static List<Node> initialiseGraph(String aGraphRepresentation) {
Map<Integer, Node> map = new TreeMap<Integer, Node>();
for ( String element : aGraphRepresentation.split(" ") ) {
if ( element.contains("-") ) {
final int index1 = Integer.valueOf(element.substring(0, 1));
final int index2 = Integer.valueOf(element.substring(element.length() - 1));
Node node1 = map.computeIfAbsent(index1, k -> new Node(index1, 0, Colour.NO_COLOUR) );
Node node2 = map.computeIfAbsent(index2, k -> new Node(index2, 0, Colour.NO_COLOUR) );
node1.neighbours.add(node2);
node2.neighbours.add(node1);
} else {
final int index = Integer.valueOf(element);
map.computeIfAbsent(index, k -> new Node(index, 0, Colour.NO_COLOUR));
}
}
 
List<Node> graph = new ArrayList<Node>(map.values());
return graph;
}
private enum Colour { BLUE, GREEN, RED, YELLOW, CYAN, ORANGE, NO_COLOUR }
private static class Node {
public Node(int aIndex, int aSaturation, Colour aColour) {
index = aIndex; saturation = aSaturation; colour = aColour;
}
private int index, saturation;
private Colour colour;
private Set<Node> neighbours = new TreeSet<Node>( (one, two) -> Integer.compare(one.index, two.index) );
}
 
}
</syntaxhighlight>
{{ out }}
<pre>
Graph: 0-1 1-2 2-0 3
Node 0: colour = BLUE neighbours = [1, 2]
Node 1: colour = GREEN neighbours = [0, 2]
Node 2: colour = RED neighbours = [0, 1]
Node 3: colour = BLUE
Number of colours used: 3
 
Graph: 1-6 1-7 1-8 2-5 2-7 2-8 3-5 3-6 3-8 4-5 4-6 4-7
Node 1: colour = BLUE neighbours = [6, 7, 8]
Node 2: colour = BLUE neighbours = [5, 7, 8]
Node 3: colour = BLUE neighbours = [5, 6, 8]
Node 4: colour = BLUE neighbours = [5, 6, 7]
Node 5: colour = GREEN neighbours = [2, 3, 4]
Node 6: colour = GREEN neighbours = [1, 3, 4]
Node 7: colour = GREEN neighbours = [1, 2, 4]
Node 8: colour = GREEN neighbours = [1, 2, 3]
Number of colours used: 2
 
Graph: 1-4 1-6 1-8 3-2 3-6 3-8 5-2 5-4 5-8 7-2 7-4 7-6
Node 1: colour = BLUE neighbours = [4, 6, 8]
Node 2: colour = GREEN neighbours = [3, 5, 7]
Node 3: colour = BLUE neighbours = [2, 6, 8]
Node 4: colour = GREEN neighbours = [1, 5, 7]
Node 5: colour = BLUE neighbours = [2, 4, 8]
Node 6: colour = GREEN neighbours = [1, 3, 7]
Node 7: colour = BLUE neighbours = [2, 4, 6]
Node 8: colour = GREEN neighbours = [1, 3, 5]
Number of colours used: 2
 
Graph: 1-6 7-1 8-1 5-2 2-7 2-8 3-5 6-3 3-8 4-5 4-6 4-7
Node 1: colour = BLUE neighbours = [6, 7, 8]
Node 2: colour = BLUE neighbours = [5, 7, 8]
Node 3: colour = BLUE neighbours = [5, 6, 8]
Node 4: colour = BLUE neighbours = [5, 6, 7]
Node 5: colour = GREEN neighbours = [2, 3, 4]
Node 6: colour = GREEN neighbours = [1, 3, 4]
Node 7: colour = GREEN neighbours = [1, 2, 4]
Node 8: colour = GREEN neighbours = [1, 2, 3]
Number of colours used: 2
</pre>
 
=={{header|jq}}==
'''Adapted from [[#Wren|Wren]]'''
 
'''Works with jq, the C implementation of jq'''
 
'''Works with gojq, the Go implementation of jq'''
 
''With a few minor tweaks, the following program also works with jaq, the Rust implementation of jq.''
 
In this entry, a graph will be represented by a JSON object
{start, nns, edges, nbr}
where .nns is the number of nodes, and .nbr is an array such
that .nbr[$i] is an array of neighbors of node $i.
The nodes are assumed to be numbered sequentially from .start onwards.
 
`Graph/2` as defined below is a constructor for such a graph.
<syntaxhighlight lang="jq">
# Add a single edge assuming it is not already there
# Input: a JSON object with at least the key .start
def addEdge($n1; $n2):
# adjust to starting node number
($n1 - .start) as $n1
| ($n2 - .start) as $n2
| .nbr[$n1] += [$n2]
| if $n1 != $n2 then .nbr[$n2] += [$n1] end ;
 
# Build a Graph object from $start and $edges assuming there are no isolated edges
def Graph($start; $edges):
([$edges[][]] | unique | length) as $nns
| {$start, # node numbering starts from $start
$nns, # number of nodes
$edges, # array of edges
nbr: [range(0;$nns) | [] ] # .nbr[$i] will be the array of neighbors of node $i
}
| reduce $edges[] as $e (.; addEdge($e[0]; $e[1]));
 
# Use greedy algorithm
def greedyColoring:
# create a list with a color for each node
.cols = [range(0; .nns) | -1] # -1 denotes no color assigned
| .cols[0] = 0 # first node assigned color 0
# create a bool list to keep track of which colors are available
| .available = [range(0; .nns) | false]
# assign colors to all nodes after the first
| reduce range(1; .nns) as $i (.;
# iterate through neighbors and mark their colors as available
reduce .nbr[$i][] as $j (.;
if .cols[$j] != -1 then .available[.cols[$j]] = true end )
# find the first available color
| (.available | index(false)) as $c
| if $c
then .cols[$i] = $c # assign it to the current node
# reset the colors of the neighbors to unavailable
# before the next iteration
| reduce .nbr[$i][] as $j (.;
if (.cols[$j] != -1) then .available[.cols[$j]] = false end )
else debug("greedyColoring unexpectedly did not find 'false'")
end )
| .cols;
 
# (n)umber of node and its (v)alence i.e. number of neighbors
def NodeVal($n; $v): {$n, $v};
 
 
### Example graphs
 
def Graph1:
{start: 0,
edges: [[0, 1], [1, 2], [2, 0], [3, 3]]} ;
 
def Graph2:
{start: 1,
edges:
[[1, 6], [1, 7], [1, 8], [2, 5], [2, 7], [2, 8],
[3, 5], [3, 6], [3, 8], [4, 5], [4, 6], [4, 7]] };
 
def Graph3:
{start: 1,
edges:
[[1, 4], [1, 6], [1, 8], [3, 2], [3, 6], [3, 8],
[5, 2], [5, 4], [5, 8], [7, 2], [7, 4], [7, 6]] };
 
def Graph4:
{start: 1,
edges:
[[1, 6], [7, 1], [8, 1], [5, 2], [2, 7], [2, 8],
[3, 5], [6, 3], [3, 8], [4, 5], [4, 6], [4, 7]] };
 
# Use `Function` to find a coloring for each of the examples given as an array:
def task(Function):
. as $examples
| length as $n
| range(0; $n) as $i
| $examples[$i] as $g
| "\nExample \($i+1)",
( $g
| Graph( .start; .edges )
| Function as $cols
| .ecount = 0 # counts edges
| .emit = null
| reduce .edges[] as $e (.;
if ($e[0] != $e[1])
then .emit += " Edge \($e[0])-\($e[1]) -> Color \($cols[$e[0] - .start]), \($cols[$e[1] - .start])\n"
| .ecount += 1
else .emit += " Node \($e[0]) -> Color \($cols[$e[0] - .start])\n"
end)
| .emit,
(reduce $cols[] as $col (.maxCol = 0; # maximum color number used
if ($col > .maxCol) then .maxCol = $col end)
|
" Number of nodes : \(.nns)",
" Number of edges : \(.ecount)",
" Number of colors : \(.maxCol+1)"
) ) ;
 
"Using the greedyColoring algorithm",
([Graph1, Graph2, Graph3, Graph4] | task(greedyColoring))
</syntaxhighlight>
{{output}}
The output is essentially the same as for the corresponding [[#Wren|Wren]] program.
 
=={{header|Julia}}==
Uses a repeated randomization of node color ordering to seek a minimum number of colors needed.
<langsyntaxhighlight lang="julia">using Random
 
"""Useful constants for the colors to be selected for nodes of the graph"""
Line 560 ⟶ 1,588:
prettyprintcolors(exgraph)
end
</langsyntaxhighlight>{{out}}
<pre>
Colors for the graph named Ex1:
Line 619 ⟶ 1,647:
</pre>
 
=={{header|PhixMathematica}} / {{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">ClearAll[ColorGroups]
Exhaustive search, trims search space to < best so far, newused improves on unique().<br>
ColorGroups[g_Graph] := Module[{h, cols, indset, diffcols},
Many more examples/testing would be needed before I would trust this the tiniest bit.
h = g;
<lang Phix>-- demo\rosetta\Graph_colouring.exw
cols = {};
constant tests = split("""
While[! EmptyGraphQ[h], maxd = RandomChoice[VertexList[h]];
0-1 1-2 2-0 3
indset = Flatten[FindIndependentVertexSet[{h, maxd}]];
1-6 1-7 1-8 2-5 2-7 2-8 3-5 3-6 3-8 4-5 4-6 4-7
AppendTo[cols, indset];
1-4 1-6 1-8 3-2 3-6 3-8 5-2 5-4 5-8 7-2 7-4 7-6
h = VertexDelete[h, indset];
1-6 7-1 8-1 5-2 2-7 2-8 3-5 6-3 3-8 4-5 4-6 4-7
];
""","\n",true)
AppendTo[cols, VertexList[h]];
diffcols = Length[cols];
cols = Catenate[Map[Thread][Rule @@@ Transpose[{cols, Range[Length[cols]]}]]];
Print[Column[Row[{"Edge ", #1, " to ", #2, " has colors ", #1 /. cols, " and ", #2 /. cols }] & @@@ EdgeList[g]]];
Print[Grid[{{"Vertices: ", VertexCount[g]}, {"Edges: ", EdgeCount[g]}, {"Colors used: ", diffcols}}]]
]
ColorGroups[Graph[Range[0, 3], {0 \[UndirectedEdge] 1, 1 \[UndirectedEdge] 2,
2 \[UndirectedEdge] 0}]]
ColorGroups[Graph[Range[8], {1 \[UndirectedEdge] 6, 1 \[UndirectedEdge] 7,
1 \[UndirectedEdge] 8, 2 \[UndirectedEdge] 5,
2 \[UndirectedEdge] 7, 2 \[UndirectedEdge] 8,
3 \[UndirectedEdge] 5, 3 \[UndirectedEdge] 6,
3 \[UndirectedEdge] 8, 4 \[UndirectedEdge] 5,
4 \[UndirectedEdge] 6, 4 \[UndirectedEdge] 7}]]
ColorGroups[Graph[Range[8], {1 \[UndirectedEdge] 4, 1 \[UndirectedEdge] 6,
1 \[UndirectedEdge] 8, 3 \[UndirectedEdge] 2,
3 \[UndirectedEdge] 6, 3 \[UndirectedEdge] 8,
5 \[UndirectedEdge] 2, 5 \[UndirectedEdge] 4,
5 \[UndirectedEdge] 8, 7 \[UndirectedEdge] 2,
7 \[UndirectedEdge] 4, 7 \[UndirectedEdge] 6}]]
ColorGroups[Graph[Range[8], {1 \[UndirectedEdge] 6, 7 \[UndirectedEdge] 1,
8 \[UndirectedEdge] 1, 5 \[UndirectedEdge] 2,
2 \[UndirectedEdge] 7, 2 \[UndirectedEdge] 8,
3 \[UndirectedEdge] 5, 6 \[UndirectedEdge] 3,
3 \[UndirectedEdge] 8, 4 \[UndirectedEdge] 5,
4 \[UndirectedEdge] 6, 4 \[UndirectedEdge] 7}]]</syntaxhighlight>
{{out}}
<pre>Edge 0 to 1 has colors 1 and 3
Edge 1 to 2 has colors 3 and 2
Edge 2 to 0 has colors 2 and 1
Vertices: 4
Edges: 3
Colors used: 3
 
Edge 1 to 6 has colors 1 and 2
function colour(sequence nodes, links, colours, soln, integer best, next, used=0)
Edge 1 to 7 has colors 1 and 2
-- fill/try each colours[next], recursing as rqd and saving any improvements.
Edge 1 to 8 has colors 1 and 2
-- nodes/links are read-only here, colours is the main workspace, soln/best are
Edge 2 to 5 has colors 1 and 2
-- the results, next is 1..length(nodes), and used is length(unique(colours)).
Edge 2 to 7 has colors 1 and 2
-- On really big graphs I might consider making nodes..best static, esp colours,
Edge 2 to 8 has colors 1 and 2
-- in which case you will probably also want a "colours[next] = 0" reset below.
Edge 3 to 5 integerhas c =colors 1 and 2
Edge 3 to 6 has colors 1 and 2
while c<best do
Edge 3 to 8 has colors 1 and 2
bool avail = true
Edge 4 to 5 has colors 1 and 2
for i=1 to length(links[next]) do
Edge 4 to 6 has colors 1 and 2
if colours[links[next][i]]==c then
Edge 4 to 7 has colors 1 and 2
avail = false
Vertices: 8
exit
Edges: 12
end if
Colors used: 2
end for
if avail then
colours[next] = c
integer newused = used + (find(c,colours)==next)
if next<length(nodes) then
{best,soln} = colour(nodes,links,colours,soln,best,next+1,newused)
elsif newused<best then
{best,soln} = {newused,colours}
end if
end if
c += 1
end while
return {best,soln}
end function
 
Edge 1 to 4 has colors 1 and 2
function add_node(sequence nodes, links, string n)
Edge 1 to 6 has colors 1 and 2
integer rdx = find(n,nodes)
Edge 1 to 8 has colors 1 and 2
if rdx=0 then
Edge 3 to 2 has colors 1 and 2
nodes = append(nodes,n)
Edge 3 to 6 has colors 1 and 2
links = append(links,{})
Edge 3 to 8 has colors 1 and 2
rdx = length(nodes)
Edge 5 to 2 has colors 1 and 2
end if
Edge 5 to 4 has colors 1 and 2
return {nodes, links, rdx}
Edge 5 to 8 has colors 1 and 2
end function
Edge 7 to 2 has colors 1 and 2
Edge 7 to 4 has colors 1 and 2
Edge 7 to 6 has colors 1 and 2
Vertices: 8
Edges: 12
Colors used: 2
 
Edge 1 to 6 has colors 2 and 1
for t=1 to length(tests) do
Edge 7 to 1 has colors 1 and 2
string tt = tests[t]
Edge 8 to 1 has colors 1 and 2
sequence lt = split(tt," "),
Edge 5 to 2 has colors 1 and 2
nodes = {},
Edge 2 to 7 has colors 2 and 1
links = {}
Edge 2 to 8 has colors 2 and 1
integer linkcount = 0, left, right
Edge 3 to 5 forhas l=1colors to2 length(lt)and do1
Edge 6 to 3 has colors 1 and 2
sequence ll = split(lt[l],"-")
Edge 3 to 8 has colors 2 and 1
{nodes, links, left} = add_node(nodes,links,ll[1])
Edge 4 to 5 has colors 2 and 1
if length(ll)=2 then
Edge 4 to 6 has colors 2 and 1
{nodes, links, right} = add_node(nodes,links,ll[2])
Edge 4 to 7 has colors 2 and 1
links[left] &= right
Vertices: 8
links[right] &= left
Edges: 12
linkcount += 1
Colors used: 2</pre>
end if
 
end for
=={{header|Nim}}==
integer ln = length(nodes)
We use the “DSatur” algorithm described here: https://en.wikipedia.org/wiki/DSatur.
printf(1,"test%d: %d nodes, %d edges, ",{t,ln,linkcount})
 
sequence colours = repeat(0,ln),
For the four examples, it gives the minimal number of colors.
soln = tagset(ln) -- fallback solution
 
integer next = 1, best = ln
<syntaxhighlight lang="nim">import algorithm, sequtils, strscans, strutils, tables
printf(1,"%d colours:%v\n",colour(nodes,links,colours,soln,best,next))
 
end for</lang>
const NoColor = 0
 
type
 
Color = range[0..63]
 
Node = ref object
num: Natural # Node number.
color: Color # Node color.
degree: Natural # Node degree.
dsat: Natural # Node Dsaturation.
neighbors: seq[Node] # List of neighbors.
 
Graph = seq[Node] # List of nodes ordered by number.
 
#---------------------------------------------------------------------------------------------------
 
proc initGraph(graphRepr: string): Graph =
## Initialize the graph from its string representation.
 
var mapping: Table[Natural, Node] # Temporary mapping.
for elem in graphRepr.splitWhitespace():
var num1, num2: int
if elem.scanf("$i-$i", num1, num2):
let node1 = mapping.mgetOrPut(num1, Node(num: num1))
let node2 = mapping.mgetOrPut(num2, Node(num: num2))
node1.neighbors.add node2
node2.neighbors.add node1
elif elem.scanf("$i", num1):
discard mapping.mgetOrPut(num1, Node(num: num1))
else:
raise newException(ValueError, "wrong description: " & elem)
 
for node in mapping.values:
node.degree = node.neighbors.len
result = sortedByIt(toSeq(mapping.values), it.num)
 
#---------------------------------------------------------------------------------------------------
 
proc numbers(nodes: seq[Node]): string =
## Return the numbers of a list of nodes.
for node in nodes:
result.addSep(" ")
result.add($node.num)
 
#---------------------------------------------------------------------------------------------------
 
proc `$`(graph: Graph): string =
## Return the description of the graph.
 
var maxColor = NoColor
for node in graph:
stdout.write "Node ", node.num, ": color = ", node.color
if node.color > maxColor: maxColor = node.color
if node.neighbors.len > 0:
echo " neighbors = ", sortedByIt(node.neighbors, it.num).numbers
else:
echo ""
echo "Number of colors: ", maxColor
 
#---------------------------------------------------------------------------------------------------
 
proc `<`(node1, node2: Node): bool =
## Comparison of nodes, by dsaturation first, then by degree.
if node1.dsat == node2.dsat: node1.degree < node2.degree
else: node1.dsat < node2.dsat
 
#---------------------------------------------------------------------------------------------------
 
proc getMaxDsatNode(nodes: var seq[Node]): Node =
## Return the node with the greatest dsaturation.
let idx = nodes.maxIndex()
result = nodes[idx]
nodes.delete(idx)
 
#---------------------------------------------------------------------------------------------------
 
proc minColor(node: Node): COLOR =
## Return the minimum available color for a node.
var colorUsed: set[Color]
for neighbor in node.neighbors:
colorUsed.incl neighbor.color
for color in 1..Color.high:
if color notin colorUsed: return color
 
#---------------------------------------------------------------------------------------------------
 
proc distinctColorsCount(node: Node): Natural =
## Return the number of distinct colors of the neighbors of a node.
var colorUsed: set[Color]
for neighbor in node.neighbors:
colorUsed.incl neighbor.color
result = colorUsed.card
 
#---------------------------------------------------------------------------------------------------
 
proc updateDsats(node: Node) =
## Update the dsaturations of the neighbors of a node.
for neighbor in node.neighbors:
if neighbor.color == NoColor:
neighbor.dsat = neighbor.distinctColorsCount()
 
#---------------------------------------------------------------------------------------------------
 
proc colorize(graphRepr: string) =
## Colorize a graph.
 
let graph = initGraph(graphRepr)
var nodes = sortedByIt(graph, -it.degree) # Copy or graph sorted by decreasing degrees.
while nodes.len > 0:
let node = nodes.getMaxDsatNode()
node.color = node.minColor()
node.updateDsats()
 
echo "Graph: ", graphRepr
echo graph
 
 
#---------------------------------------------------------------------------------------------------
 
when isMainModule:
colorize("0-1 1-2 2-0 3")
colorize("1-6 1-7 1-8 2-5 2-7 2-8 3-5 3-6 3-8 4-5 4-6 4-7")
colorize("1-4 1-6 1-8 3-2 3-6 3-8 5-2 5-4 5-8 7-2 7-4 7-6")
colorize("1-6 7-1 8-1 5-2 2-7 2-8 3-5 6-3 3-8 4-5 4-6 4-7")</syntaxhighlight>
 
{{out}}
<pre>Graph: 0-1 1-2 2-0 3
Node 0: color = 1 neighbors = 1 2
Node 1: color = 2 neighbors = 0 2
Node 2: color = 3 neighbors = 0 1
Node 3: color = 1
Number of colors: 3
 
Graph: 1-6 1-7 1-8 2-5 2-7 2-8 3-5 3-6 3-8 4-5 4-6 4-7
Node 1: color = 1 neighbors = 6 7 8
Node 2: color = 1 neighbors = 5 7 8
Node 3: color = 1 neighbors = 5 6 8
Node 4: color = 1 neighbors = 5 6 7
Node 5: color = 2 neighbors = 2 3 4
Node 6: color = 2 neighbors = 1 3 4
Node 7: color = 2 neighbors = 1 2 4
Node 8: color = 2 neighbors = 1 2 3
Number of colors: 2
 
Graph: 1-4 1-6 1-8 3-2 3-6 3-8 5-2 5-4 5-8 7-2 7-4 7-6
Node 1: color = 1 neighbors = 4 6 8
Node 2: color = 2 neighbors = 3 5 7
Node 3: color = 1 neighbors = 2 6 8
Node 4: color = 2 neighbors = 1 5 7
Node 5: color = 1 neighbors = 2 4 8
Node 6: color = 2 neighbors = 1 3 7
Node 7: color = 1 neighbors = 2 4 6
Node 8: color = 2 neighbors = 1 3 5
Number of colors: 2
 
Graph: 1-6 7-1 8-1 5-2 2-7 2-8 3-5 6-3 3-8 4-5 4-6 4-7
Node 1: color = 1 neighbors = 6 7 8
Node 2: color = 1 neighbors = 5 7 8
Node 3: color = 1 neighbors = 5 6 8
Node 4: color = 1 neighbors = 5 6 7
Node 5: color = 2 neighbors = 2 3 4
Node 6: color = 2 neighbors = 1 3 4
Node 7: color = 2 neighbors = 1 2 4
Node 8: color = 2 neighbors = 1 2 3
Number of colors: 2</pre>
 
=={{header|Perl}}==
{{trans|Raku}}
<syntaxhighlight lang="perl">use strict;
use warnings;
no warnings 'uninitialized';
use feature 'say';
use constant True => 1;
use List::Util qw(head uniq);
 
sub GraphNodeColor {
my(%OneMany, %NodeColor, %NodePool, @ColorPool);
my(@data) = @_;
 
for (@data) {
my($a,$b) = @$_;
push @{$OneMany{$a}}, $b;
push @{$OneMany{$b}}, $a;
}
 
@ColorPool = 0 .. -1 + scalar %OneMany;
$NodePool{$_} = True for keys %OneMany;
 
if ($OneMany{''}) { # skip islanders for now
delete $NodePool{$_} for @{$OneMany{''}};
delete $NodePool{''};
}
 
while (%NodePool) {
my $color = shift @ColorPool;
my %TempPool = %NodePool;
 
while (my $n = head 1, sort keys %TempPool) {
$NodeColor{$n} = $color;
delete $TempPool{$n};
delete $TempPool{$_} for @{$OneMany{$n}} ; # skip neighbors as well
delete $NodePool{$n};
}
 
if ($OneMany{''}) { # islanders use an existing color
$NodeColor{$_} = head 1, sort values %NodeColor for @{$OneMany{''}};
}
}
%NodeColor
}
 
my @DATA = (
[ [1,2],[2,3],[3,1],[4,undef],[5,undef],[6,undef] ],
[ [1,6],[1,7],[1,8],[2,5],[2,7],[2,8],[3,5],[3,6],[3,8],[4,5],[4,6],[4,7] ],
[ [1,4],[1,6],[1,8],[3,2],[3,6],[3,8],[5,2],[5,4],[5,8],[7,2],[7,4],[7,6] ],
[ [1,6],[7,1],[8,1],[5,2],[2,7],[2,8],[3,5],[6,3],[3,8],[4,5],[4,6],[4,7] ]
);
 
for my $d (@DATA) {
my %result = GraphNodeColor @$d;
 
my($graph,$colors);
$graph .= '(' . join(' ', @$_) . '), ' for @$d;
$colors .= ' ' . $result{$$_[0]} . '-' . ($result{$$_[1]} // '') . ' ' for @$d;
 
say 'Graph : ' . $graph =~ s/,\s*$//r;
say 'Colors : ' . $colors;
say 'Nodes : ' . keys %result;
say 'Edges : ' . @$d;
say 'Unique : ' . uniq values %result;
say '';
}</syntaxhighlight>
{{out}}
<pre>Graph : (1 2), (2 3), (3 1), (4 ), (5 ), (6 )
Colors : 0-1 1-2 2-0 0- 0- 0-
Nodes : 6
Edges : 6
Unique : 3
 
Graph : (1 6), (1 7), (1 8), (2 5), (2 7), (2 8), (3 5), (3 6), (3 8), (4 5), (4 6), (4 7)
Colors : 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1
Nodes : 8
Edges : 12
Unique : 2
 
Graph : (1 4), (1 6), (1 8), (3 2), (3 6), (3 8), (5 2), (5 4), (5 8), (7 2), (7 4), (7 6)
Colors : 0-1 0-2 0-3 1-0 1-2 1-3 2-0 2-1 2-3 3-0 3-1 3-2
Nodes : 8
Edges : 12
Unique : 4
 
Graph : (1 6), (7 1), (8 1), (5 2), (2 7), (2 8), (3 5), (6 3), (3 8), (4 5), (4 6), (4 7)
Colors : 0-1 1-0 1-0 1-0 0-1 0-1 0-1 1-0 0-1 0-1 0-1 0-1
Nodes : 8
Edges : 12
Unique : 2</pre>
 
=={{header|Phix}}==
Exhaustive search, trims search space to < best so far, newused improves on unique().<br>
Many more examples/testing would be needed before I would trust this the tiniest bit.<br>
NB: As per talk page, when writing this I did not remotely imagine it might be used on over 400,000 nodes with over 3 million links...
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">-- demo\rosetta\Graph_colouring.exw</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">tests</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"""
0-1 1-2 2-0 3
1-6 1-7 1-8 2-5 2-7 2-8 3-5 3-6 3-8 4-5 4-6 4-7
1-4 1-6 1-8 3-2 3-6 3-8 5-2 5-4 5-8 7-2 7-4 7-6
1-6 7-1 8-1 5-2 2-7 2-8 3-5 6-3 3-8 4-5 4-6 4-7
"""</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">true</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">colour</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">nodes</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">links</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">colours</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">soln</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">best</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">next</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">used</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- fill/try each colours[next], recursing as rqd and saving any improvements.
-- nodes/links are read-only here, colours is the main workspace, soln/best are
-- the results, next is 1..length(nodes), and used is length(unique(colours)).
-- On really big graphs I might consider making nodes..best static, esp colours,
-- in which case you will probably also want a "colours[next] = 0" reset below.</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">colours</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">colours</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">c</span><span style="color: #0000FF;"><</span><span style="color: #000000;">best</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">avail</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">links</span><span style="color: #0000FF;">[</span><span style="color: #000000;">next</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">colours</span><span style="color: #0000FF;">[</span><span style="color: #000000;">links</span><span style="color: #0000FF;">[</span><span style="color: #000000;">next</span><span style="color: #0000FF;">][</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]]==</span><span style="color: #000000;">c</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">avail</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
<span style="color: #008080;">exit</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">avail</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">colours</span><span style="color: #0000FF;">[</span><span style="color: #000000;">next</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">c</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">newused</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">used</span> <span style="color: #0000FF;">+</span> <span style="color: #0000FF;">(</span><span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">,</span><span style="color: #000000;">colours</span><span style="color: #0000FF;">)==</span><span style="color: #000000;">next</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">next</span><span style="color: #0000FF;"><</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nodes</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">best</span><span style="color: #0000FF;">,</span><span style="color: #000000;">soln</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">colour</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nodes</span><span style="color: #0000FF;">,</span><span style="color: #000000;">links</span><span style="color: #0000FF;">,</span><span style="color: #000000;">colours</span><span style="color: #0000FF;">,</span><span style="color: #000000;">soln</span><span style="color: #0000FF;">,</span><span style="color: #000000;">best</span><span style="color: #0000FF;">,</span><span style="color: #000000;">next</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">newused</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">newused</span><span style="color: #0000FF;"><</span><span style="color: #000000;">best</span> <span style="color: #008080;">then</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">best</span><span style="color: #0000FF;">,</span><span style="color: #000000;">soln</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">newused</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">colours</span><span style="color: #0000FF;">)}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">c</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">best</span><span style="color: #0000FF;">,</span><span style="color: #000000;">soln</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">add_node</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">nodes</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">links</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">string</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">rdx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nodes</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">rdx</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">nodes</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nodes</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">links</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">links</span><span style="color: #0000FF;">,{})</span>
<span style="color: #000000;">rdx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nodes</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">nodes</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">links</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">rdx</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">t</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">tt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tests</span><span style="color: #0000FF;">[</span><span style="color: #000000;">t</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">lt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tt</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" "</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">nodes</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{},</span>
<span style="color: #000000;">links</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">linkcount</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">left</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">right</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">l</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lt</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">ll</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">l</span><span style="color: #0000FF;">],</span><span style="color: #008000;">"-"</span><span style="color: #0000FF;">)</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">nodes</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">links</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">left</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">add_node</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nodes</span><span style="color: #0000FF;">),</span><span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">links</span><span style="color: #0000FF;">),</span><span style="color: #000000;">ll</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ll</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">2</span> <span style="color: #008080;">then</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">nodes</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">links</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">right</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">add_node</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nodes</span><span style="color: #0000FF;">),</span><span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">links</span><span style="color: #0000FF;">),</span><span style="color: #000000;">ll</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">])</span>
<span style="color: #000000;">links</span><span style="color: #0000FF;">[</span><span style="color: #000000;">left</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">links</span><span style="color: #0000FF;">[</span><span style="color: #000000;">left</span><span style="color: #0000FF;">])&</span><span style="color: #000000;">right</span>
<span style="color: #000000;">links</span><span style="color: #0000FF;">[</span><span style="color: #000000;">right</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">links</span><span style="color: #0000FF;">[</span><span style="color: #000000;">right</span><span style="color: #0000FF;">])&</span><span style="color: #000000;">left</span>
<span style="color: #000000;">linkcount</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ln</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nodes</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"test%d: %d nodes, %d edges, "</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">t</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ln</span><span style="color: #0000FF;">,</span><span style="color: #000000;">linkcount</span><span style="color: #0000FF;">})</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">colours</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ln</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">soln</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ln</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- fallback solution</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">next</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">best</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ln</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%d colours:%v\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">colour</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nodes</span><span style="color: #0000FF;">,</span><span style="color: #000000;">links</span><span style="color: #0000FF;">,</span><span style="color: #000000;">colours</span><span style="color: #0000FF;">,</span><span style="color: #000000;">soln</span><span style="color: #0000FF;">,</span><span style="color: #000000;">best</span><span style="color: #0000FF;">,</span><span style="color: #000000;">next</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 701 ⟶ 2,091:
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">import re
from collections import defaultdict
from itertools import count
Line 773 ⟶ 2,163:
]:
g = Graph(name, connections)
g.greedy_colour()</langsyntaxhighlight>
 
{{out}}
Line 842 ⟶ 2,232:
=={{header|Raku}}==
(formerly Perl 6)
<syntaxhighlight lang="raku" line>sub GraphNodeColor(@RAW) {
<lang perl6>#!/usr/bin/env perl6
 
sub GraphNodeColor(@RAW) {
my %OneMany = my %NodeColor;
for @RAW { %OneMany{$_[0]}.push: $_[1] ; %OneMany{$_[1]}.push: $_[0] }
Line 881 ⟶ 2,269:
say "Edges : ", $_.elems;
say "Colors : ", %out.values.Set.elems;
}</langsyntaxhighlight>
{{out}}
<pre>DATA : [(0 1) (1 2) (2 0) (3 NaN) (4 NaN) (5 NaN)]
Line 945 ⟶ 2,333:
Edges : 12
Colors : 2</pre>
 
=={{header|Wren}}==
{{trans|Go}}
{{libheader|Wren-dynamic}}
{{libheader|Wren-sort}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="wren">import "./dynamic" for Struct
import "./sort" for Sort
import "./fmt" for Fmt
 
// (n)umber of node and its (v)alence i.e. number of neighbors
var NodeVal = Struct.create("NodeVal", ["n", "v"])
 
class Graph {
construct new(nn, st) {
_nn = nn // number of nodes
_st = st // node numbering starts from
_nbr = List.filled(nn, null) // neighbor list for each node
for (i in 0...nn) _nbr[i] = []
}
 
nn { _nn }
st { _st }
 
// Note that this creates a single 'virtual' edge for an isolated node.
addEdge(n1, n2) {
// adjust to starting node number
n1 = n1 - _st
n2 = n2 - _st
_nbr[n1].add(n2)
if (n1 != n2) _nbr[n2].add(n1)
}
 
// Uses 'greedy' algorithm.
greedyColoring {
// create a list with a color for each node
var cols = List.filled(_nn, -1) // -1 denotes no color assigned
cols[0] = 0 // first node assigned color 0
// create a bool list to keep track of which colors are available
var available = List.filled(_nn, false)
// assign colors to all nodes after the first
for (i in 1..._nn) {
// iterate through neighbors and mark their colors as available
for (j in _nbr[i]) {
if (cols[j] != -1) available[cols[j]] = true
}
// find the first available color
var c = available.indexOf(false)
cols[i] = c // assign it to the current node
// reset the neighbors' colors to unavailable
// before the next iteration
for (j in _nbr[i]) {
if (cols[j] != -1) available[cols[j]] = false
}
}
return cols
}
 
// Uses Welsh-Powell algorithm.
wpColoring {
// create NodeVal for each node
var nvs = List.filled(_nn, null)
for (i in 0..._nn) {
var v = _nbr[i].count
if (v == 1 && _nbr[i][0] == i) { // isolated node
v = 0
}
nvs[i] = NodeVal.new(i, v)
}
// sort the NodeVals in descending order by valence
var cmp = Fn.new { |nv1, nv2| (nv2.v - nv1.v).sign }
Sort.insertion(nvs, cmp) // stable sort
 
// create colors list with entries for each node
var cols = List.filled(_nn, -1) // set all nodes to no color (-1) initially
var currCol = 0 // start with color 0
for (f in 0..._nn-1) {
var h = nvs[f].n
if (cols[h] != -1) { // already assigned a color
continue
}
cols[h] = currCol
// assign same color to all subsequent uncolored nodes which are
// not connected to a previous colored one
var i = f + 1
while (i < _nn) {
var outer = false
var j = nvs[i].n
if (cols[j] != -1) { // already colored
i = i + 1
continue
}
var k = f
while (k < i) {
var l = nvs[k].n
if (cols[l] == -1) { // not yet colored
k = k + 1
continue
}
if (_nbr[j].contains(l)) {
outer = true
break // node j is connected to an earlier colored node
}
k = k + 1
}
if (!outer) cols[j] = currCol
i = i + 1
}
currCol = currCol + 1
}
return cols
}
}
 
var fns = [Fn.new { |g| g.greedyColoring }, Fn.new { |g| g.wpColoring }]
var titles = ["'Greedy'", "Welsh-Powell"]
var nns = [4, 8, 8, 8]
var starts = [0, 1, 1, 1]
var edges1 = [[0, 1], [1, 2], [2, 0], [3, 3]]
var edges2 = [[1, 6], [1, 7], [1, 8], [2, 5], [2, 7], [2, 8],
[3, 5], [3, 6], [3, 8], [4, 5], [4, 6], [4, 7]]
var edges3 = [[1, 4], [1, 6], [1, 8], [3, 2], [3, 6], [3, 8],
[5, 2], [5, 4], [5, 8], [7, 2], [7, 4], [7, 6]]
var edges4 = [[1, 6], [7, 1], [8, 1], [5, 2], [2, 7], [2, 8],
[3, 5], [6, 3], [3, 8], [4, 5], [4, 6], [4, 7]]
var j = 0
for (fn in fns) {
System.print("Using the %(titles[j]) algorithm:\n")
var i = 0
for (edges in [edges1, edges2, edges3, edges4]) {
System.print(" Example %(i+1)")
var g = Graph.new(nns[i], starts[i])
for (e in edges) g.addEdge(e[0], e[1])
var cols = fn.call(g)
var ecount = 0 // counts edges
for (e in edges) {
if (e[0] != e[1]) {
Fmt.print(" Edge $d-$d -> Color $d, $d", e[0], e[1],
cols[e[0]-g.st], cols[e[1]-g.st])
ecount = ecount + 1
} else {
Fmt.print(" Node $d -> Color $d\n", e[0], cols[e[0]-g.st])
}
}
var maxCol = 0 // maximum color number used
for (col in cols) {
if (col > maxCol) maxCol = col
}
System.print(" Number of nodes : %(nns[i])")
System.print(" Number of edges : %(ecount)")
System.print(" Number of colors : %(maxCol+1)")
System.print()
i = i + 1
}
j = j + 1
}</syntaxhighlight>
 
{{out}}
<pre>
Using the 'Greedy' algorithm:
 
Example 1
Edge 0-1 -> Color 0, 1
Edge 1-2 -> Color 1, 2
Edge 2-0 -> Color 2, 0
Node 3 -> Color 0
 
Number of nodes : 4
Number of edges : 3
Number of colors : 3
 
Example 2
Edge 1-6 -> Color 0, 1
Edge 1-7 -> Color 0, 1
Edge 1-8 -> Color 0, 1
Edge 2-5 -> Color 0, 1
Edge 2-7 -> Color 0, 1
Edge 2-8 -> Color 0, 1
Edge 3-5 -> Color 0, 1
Edge 3-6 -> Color 0, 1
Edge 3-8 -> Color 0, 1
Edge 4-5 -> Color 0, 1
Edge 4-6 -> Color 0, 1
Edge 4-7 -> Color 0, 1
Number of nodes : 8
Number of edges : 12
Number of colors : 2
 
Example 3
Edge 1-4 -> Color 0, 1
Edge 1-6 -> Color 0, 2
Edge 1-8 -> Color 0, 3
Edge 3-2 -> Color 1, 0
Edge 3-6 -> Color 1, 2
Edge 3-8 -> Color 1, 3
Edge 5-2 -> Color 2, 0
Edge 5-4 -> Color 2, 1
Edge 5-8 -> Color 2, 3
Edge 7-2 -> Color 3, 0
Edge 7-4 -> Color 3, 1
Edge 7-6 -> Color 3, 2
Number of nodes : 8
Number of edges : 12
Number of colors : 4
 
Example 4
Edge 1-6 -> Color 0, 1
Edge 7-1 -> Color 1, 0
Edge 8-1 -> Color 1, 0
Edge 5-2 -> Color 1, 0
Edge 2-7 -> Color 0, 1
Edge 2-8 -> Color 0, 1
Edge 3-5 -> Color 0, 1
Edge 6-3 -> Color 1, 0
Edge 3-8 -> Color 0, 1
Edge 4-5 -> Color 0, 1
Edge 4-6 -> Color 0, 1
Edge 4-7 -> Color 0, 1
Number of nodes : 8
Number of edges : 12
Number of colors : 2
 
Using the Welsh-Powell algorithm:
 
Example 1
Edge 0-1 -> Color 0, 1
Edge 1-2 -> Color 1, 2
Edge 2-0 -> Color 2, 0
Node 3 -> Color 0
 
Number of nodes : 4
Number of edges : 3
Number of colors : 3
 
Example 2
Edge 1-6 -> Color 0, 1
Edge 1-7 -> Color 0, 1
Edge 1-8 -> Color 0, 1
Edge 2-5 -> Color 0, 1
Edge 2-7 -> Color 0, 1
Edge 2-8 -> Color 0, 1
Edge 3-5 -> Color 0, 1
Edge 3-6 -> Color 0, 1
Edge 3-8 -> Color 0, 1
Edge 4-5 -> Color 0, 1
Edge 4-6 -> Color 0, 1
Edge 4-7 -> Color 0, 1
Number of nodes : 8
Number of edges : 12
Number of colors : 2
 
Example 3
Edge 1-4 -> Color 0, 1
Edge 1-6 -> Color 0, 2
Edge 1-8 -> Color 0, 3
Edge 3-2 -> Color 1, 0
Edge 3-6 -> Color 1, 2
Edge 3-8 -> Color 1, 3
Edge 5-2 -> Color 2, 0
Edge 5-4 -> Color 2, 1
Edge 5-8 -> Color 2, 3
Edge 7-2 -> Color 3, 0
Edge 7-4 -> Color 3, 1
Edge 7-6 -> Color 3, 2
Number of nodes : 8
Number of edges : 12
Number of colors : 4
 
Example 4
Edge 1-6 -> Color 0, 1
Edge 7-1 -> Color 1, 0
Edge 8-1 -> Color 1, 0
Edge 5-2 -> Color 1, 0
Edge 2-7 -> Color 0, 1
Edge 2-8 -> Color 0, 1
Edge 3-5 -> Color 0, 1
Edge 6-3 -> Color 1, 0
Edge 3-8 -> Color 0, 1
Edge 4-5 -> Color 0, 1
Edge 4-6 -> Color 0, 1
Edge 4-7 -> Color 0, 1
Number of nodes : 8
Number of edges : 12
Number of colors : 2
</pre>
 
=={{header|zkl}}==
<langsyntaxhighlight lang="zkl">fcn colorGraph(nodeStr){ // "0-1 1-2 2-0 3"
numEdges,graph := 0,Dictionary(); // ( 0:(1,2), 1:L(0,2), 2:(1,0), 3:() )
foreach n in (nodeStr.split(" ")){ // parse string to graph
Line 965 ⟶ 2,638:
});
return(graph,colors,numEdges)
}</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">fcn printColoredGraph(graphStr){
graph,colors,numEdges := colorGraph(graphStr);
nodes:=graph.keys.sort();
Line 983 ⟶ 2,656:
colors.values.pump(Dictionary().add.fp1(Void)).len()); // create set, count
println();
}</langsyntaxhighlight>
<syntaxhighlight lang="zkl">graphs:=T(
"0-1 1-2 2-0 3",
"1-6 1-7 1-8 2-5 2-7 2-8 3-5 3-6 3-8 4-5 4-6 4-7",
"1-4 1-6 1-8 3-2 3-6 3-8 5-2 5-4 5-8 7-2 7-4 7-6",
"1-6 7-1 8-1 5-2 2-7 2-8 3-5 6-3 3-8 4-5 4-6 4-7"
);
graphs.apply2(printColoredGraph);</syntaxhighlight>
{{out}}
<pre style="height:45ex">
2,502

edits