150 lines
5.2 KiB
Text
150 lines
5.2 KiB
Text
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
|
|
}
|