Task: Graph colouring




Go: package main

import (
    "fmt"
    "sort"
)

type graph struct {
    nn  int     
    st  int     
    nbr [][]int 
}

type nodeval struct {
    n int 
    v int 
}

func contains(s []int, n int) bool {
    for _, e := range s {
        if e == n {
            return true
        }
    }
    return false
}

func newGraph(nn, st int) graph {
    nbr := make([][]int, nn)
    return graph{nn, st, nbr}
}


func (g graph) addEdge(n1, n2 int) {
    n1, n2 = n1-g.st, n2-g.st 
    g.nbr[n1] = append(g.nbr[n1], n2)
    if n1 != n2 {
        g.nbr[n2] = append(g.nbr[n2], n1)
    }
}


func (g graph) greedyColoring() []int {
    
    cols := make([]int, g.nn) 
    for i := 1; i < g.nn; i++ {
        cols[i] = -1 
    }
    
    available := make([]bool, g.nn) 
    
    for i := 1; i < g.nn; i++ {
        
        for _, j := range g.nbr[i] {
            if cols[j] != -1 {
                available[cols[j]] = true
            }
        }
        
        c := 0
        for ; c < g.nn; c++ {
            if !available[c] {
                break
            }
        }
        cols[i] = c 
        
        
        for _, j := range g.nbr[i] {
            if cols[j] != -1 {
                available[cols[j]] = false
            }
        }
    }
    return cols
}


func (g graph) wpColoring() []int {
    
    nvs := make([]nodeval, g.nn)
    for i := 0; i < g.nn; i++ {
        v := len(g.nbr[i])
        if v == 1 && g.nbr[i][0] == i { 
            v = 0
        }
        nvs[i] = nodeval{i, v}
    }
    
    sort.Slice(nvs, func(i, j int) bool {
        return nvs[i].v > nvs[j].v
    })
    
    cols := make([]int, g.nn)
    for i := range cols {
        cols[i] = -1 
    }
    currCol := 0 
    for f := 0; f < g.nn-1; f++ {
        h := nvs[f].n
        if cols[h] != -1 { 
            continue
        }
        cols[h] = currCol
        
        
    outer:
        for i := f + 1; i < g.nn; i++ {
            j := nvs[i].n
            if cols[j] != -1 { 
                continue
            }
            for k := f; k < i; k++ {
                l := nvs[k].n
                if cols[l] == -1 { 
                    continue
                }
                if contains(g.nbr[j], l) {
                    continue outer 
                }
            }
            cols[j] = currCol
        }
        currCol++
    }
    return cols
}

func main() {
    fns := [](func(graph) []int){graph.greedyColoring, graph.wpColoring}
    titles := []string{"'Greedy'", "Welsh-Powell"}
    nns := []int{4, 8, 8, 8}
    starts := []int{0, 1, 1, 1}
    edges1 := [][2]int{{0, 1}, {1, 2}, {2, 0}, {3, 3}}
    edges2 := [][2]int{{1, 6}, {1, 7}, {1, 8}, {2, 5}, {2, 7}, {2, 8},
        {3, 5}, {3, 6}, {3, 8}, {4, 5}, {4, 6}, {4, 7}}
    edges3 := [][2]int{{1, 4}, {1, 6}, {1, 8}, {3, 2}, {3, 6}, {3, 8},
        {5, 2}, {5, 4}, {5, 8}, {7, 2}, {7, 4}, {7, 6}}
    edges4 := [][2]int{{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 j, fn := range fns {
        fmt.Println("Using the", titles[j], "algorithm:\n")
        for i, edges := range [][][2]int{edges1, edges2, edges3, edges4} {
            fmt.Println("  Example", i+1)
            g := newGraph(nns[i], starts[i])
            for _, e := range edges {
                g.addEdge(e[0], e[1])
            }
            cols := fn(g)
            ecount := 0 
            for _, e := range edges {
                if e[0] != e[1] {
                    fmt.Printf("    Edge  %d-%d -> Color %d, %d\n", e[0], e[1],
                        cols[e[0]-g.st], cols[e[1]-g.st])
                    ecount++
                } else {
                    fmt.Printf("    Node  %d   -> Color %d\n", e[0], cols[e[0]-g.st])
                }
            }
            maxCol := 0 
            for _, col := range cols {
                if col > maxCol {
                    maxCol = col
                }
            }
            fmt.Println("    Number of nodes  :", nns[i])
            fmt.Println("    Number of edges  :", ecount)
            fmt.Println("    Number of colors :", maxCol+1)
            fmt.Println()
        }
    }
}




Python: import re
from collections import defaultdict
from itertools import count


connection_re = r

class Graph:

    def __init__(self, name, connections):
        self.name = name
        self.connections = connections
        g = self.graph = defaultdict(list)  

        matches = re.finditer(connection_re, connections,
                              re.MULTILINE | re.VERBOSE)
        for match in matches:
            n1, n2, n = match.groups()
            if n:
                g[n] += []
            else:
                g[n1].append(n2)    
                g[n2].append(n1)

    def greedy_colour(self, order=None):
        "Greedy colourisation algo."
        if order is None:
            order = self.graph      
        colour = self.colour = {}
        neighbours = self.graph
        for node in order:
            used_neighbour_colours = (colour[nbr] for nbr in neighbours[node]
                                      if nbr in colour)
            colour[node] = first_avail_int(used_neighbour_colours)
        self.pp_colours()
        return colour

    def pp_colours(self):
        print(f"\n{self.name}")
        c = self.colour
        e = canonical_edges = set()
        for n1, neighbours in sorted(self.graph.items()):
            if neighbours:
                for n2 in neighbours:
                    edge = tuple(sorted([n1, n2]))
                    if edge not in canonical_edges:
                        print(f"       {n1}-{n2}: Colour: {c[n1]}, {c[n2]}")
                        canonical_edges.add(edge)
            else:
                print(f"         {n1}: Colour: {c[n1]}")
        lc = len(set(c.values()))
        print(f"    


def first_avail_int(data):
    "return lowest int 0... not in data"
    d = set(data)
    for i in count():
        if i not in d:
            return i


if __name__ == '__main__':
    for name, connections in [
            ('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"),
            ]:
        g = Graph(name, connections)
        g.greedy_colour()