github.com/gopherd/gonum@v0.0.4/graph/coloring/coloring.go (about)

     1  // Copyright ©2021 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // See Lewis, A Guide to Graph Colouring: Algorithms and Applications
     6  // doi:10.1007/978-3-319-25730-3 for significant discussion of approaches.
     7  
     8  package coloring
     9  
    10  import (
    11  	"errors"
    12  	"sort"
    13  
    14  	"math/rand"
    15  
    16  	"github.com/gopherd/gonum/graph"
    17  	"github.com/gopherd/gonum/graph/internal/set"
    18  	"github.com/gopherd/gonum/graph/iterator"
    19  	"github.com/gopherd/gonum/graph/topo"
    20  )
    21  
    22  // ErrInvalidPartialColoring is returned when a partial coloring
    23  // is provided for a graph with inadmissible color assignments.
    24  var ErrInvalidPartialColoring = errors.New("coloring: invalid partial coloring")
    25  
    26  // Sets returns the mapping from colors to sets of node IDs. Each set of
    27  // node IDs is sorted by ascending value.
    28  func Sets(colors map[int64]int) map[int][]int64 {
    29  	sets := make(map[int][]int64)
    30  	for id, c := range colors {
    31  		sets[c] = append(sets[c], id)
    32  	}
    33  	for _, s := range sets {
    34  		sort.Slice(s, func(i, j int) bool { return s[i] < s[j] })
    35  	}
    36  	return sets
    37  }
    38  
    39  // Dsatur returns an approximate minimal chromatic number of g and a
    40  // corresponding vertex coloring using the heuristic Dsatur coloring algorithm.
    41  // If a partial coloring is provided the coloring will be consistent with
    42  // that partial coloring if possible. Otherwise Dsatur will return
    43  // ErrInvalidPartialColoring.
    44  // See Brélaz doi:10.1145/359094.359101 for details of the algorithm.
    45  func Dsatur(g graph.Undirected, partial map[int64]int) (k int, colors map[int64]int, err error) {
    46  	nodes := g.Nodes()
    47  	n := nodes.Len()
    48  	if n == 0 {
    49  		return
    50  	}
    51  	partial, ok := newPartial(partial, g)
    52  	if !ok {
    53  		return -1, nil, ErrInvalidPartialColoring
    54  	}
    55  	order := bySaturationDegree(nodes, g, partial)
    56  	order.heuristic = order.dsatur
    57  	k, colors = greedyColoringOf(g, order, order.colors)
    58  	return k, colors, nil
    59  }
    60  
    61  // Terminator is a cancellation-only context type. A context.Context
    62  // may be used as a Terminator.
    63  type Terminator interface {
    64  	// Done returns a channel that is closed when work
    65  	// should be terminated. Done may return nil if this
    66  	// work can never be canceled.
    67  	// Successive calls to Done should return the same value.
    68  	Done() <-chan struct{}
    69  
    70  	// If Done is not yet closed, Err returns nil.
    71  	// If Done is closed, Err returns a non-nil error
    72  	// explaining why.
    73  	// After Err returns a non-nil error, successive
    74  	// calls to Err should return the same error.
    75  	Err() error
    76  }
    77  
    78  // DsaturExact returns the exact minimal chromatic number of g and a
    79  // corresponding vertex coloring using the branch-and-bound Dsatur coloring
    80  // algorithm of Brélaz. If the provided terminator is cancelled or times out
    81  // before completion, the terminator's reason for termination will be returned
    82  // along with a potentially sub-optimal chromatic number and coloring. If
    83  // term is nil, DsaturExact will run to completion.
    84  // See Brélaz doi:10.1145/359094.359101 for details of the algorithm.
    85  func DsaturExact(term Terminator, g graph.Undirected) (k int, colors map[int64]int, err error) {
    86  	// This is implemented essentially as described in algorithm 1 of
    87  	// doi:10.1002/net.21716 with the exception that we obtain a
    88  	// tighter upper bound by doing a single run of an approximate
    89  	// Brélaz Dsatur coloring, using the result if the recurrence is
    90  	// cancelled.
    91  	// We also use the initial maximum clique as a starting point for
    92  	// the exact search. If there is more than one maxumum clique, we
    93  	// need to ensure that we pick the one that will lead us down the
    94  	// easiest branch of the search tree. This will be the maximum
    95  	// clique with the lowest degree into the remainder of the graph.
    96  
    97  	nodes := g.Nodes()
    98  	n := nodes.Len()
    99  	if n == 0 {
   100  		return
   101  	}
   102  
   103  	lb, maxClique, cliques := maximumClique(g)
   104  	if lb == n {
   105  		return lb, colorClique(maxClique), nil
   106  	}
   107  
   108  	order := bySaturationDegree(nodes, g, make(map[int64]int))
   109  	order.heuristic = order.dsatur
   110  	// Find initial coloring via Dsatur heuristic.
   111  	ub, initial := greedyColoringOf(g, order, order.colors)
   112  	if lb == ub {
   113  		return ub, initial, nil
   114  	}
   115  
   116  	selector := &order.saturationDegree
   117  	cand := newDsaturColoring(order.nodes, bestMaximumClique(g, cliques))
   118  	k, colors, err = dSaturExact(term, selector, cand, len(cand.colors), ub, nil)
   119  	if colors == nil {
   120  		return ub, initial, err
   121  	}
   122  	if k == lb {
   123  		err = nil
   124  	}
   125  	return k, colors, err
   126  }
   127  
   128  // dSaturColoring is a partial graph coloring.
   129  type dSaturColoring struct {
   130  	colors    map[int64]int
   131  	uncolored set.Int64s
   132  }
   133  
   134  // newDsaturColoring returns a dSaturColoring representing a partial coloring
   135  // of a graph with the given nodes and colors.
   136  func newDsaturColoring(nodes []graph.Node, colors map[int64]int) dSaturColoring {
   137  	uncolored := make(set.Int64s)
   138  	for _, v := range nodes {
   139  		vid := v.ID()
   140  		if _, ok := colors[vid]; !ok {
   141  			uncolored.Add(vid)
   142  		}
   143  	}
   144  	return dSaturColoring{
   145  		colors:    colors,
   146  		uncolored: uncolored,
   147  	}
   148  }
   149  
   150  // color moves a node from the uncolored set to the colored set.
   151  func (c dSaturColoring) color(id int64) {
   152  	if !c.uncolored.Has(id) {
   153  		if _, ok := c.colors[id]; ok {
   154  			panic("coloring: coloring already colored node")
   155  		}
   156  		panic("coloring: coloring non-existent node")
   157  	}
   158  	// The node has its uncolored mark removed, but is
   159  	// not explicitly colored until the dSaturExact
   160  	// caller has completed its recursive exploration
   161  	// of the feasible colors.
   162  	c.uncolored.Remove(id)
   163  }
   164  
   165  // uncolor moves a node from the colored set to the uncolored set.
   166  func (c dSaturColoring) uncolor(id int64) {
   167  	if _, ok := c.colors[id]; !ok {
   168  		if c.uncolored.Has(id) {
   169  			panic("coloring: uncoloring already uncolored node")
   170  		}
   171  		panic("coloring: uncoloring non-existent node")
   172  	}
   173  	delete(c.colors, id)
   174  	c.uncolored.Add(id)
   175  }
   176  
   177  // dSaturExact recursively searches for an exact mimimum vertex coloring of the
   178  // full graph in cand. If no chromatic number lower than ub is found, colors is
   179  // returned as nil.
   180  func dSaturExact(term Terminator, selector *saturationDegree, cand dSaturColoring, k, ub int, best map[int64]int) (newK int, colors map[int64]int, err error) {
   181  	if len(cand.uncolored) == 0 {
   182  		// In the published algorithm, this is guarded by k < ub,
   183  		// but dSaturExact is never called with k >= ub; in the
   184  		// initial call we have excluded cases where k == ub and
   185  		// it cannot be greater, and in the recursive call, we
   186  		// have already checked that k < ub.
   187  		return k, clone(cand.colors), nil
   188  	}
   189  
   190  	if term != nil {
   191  		select {
   192  		case <-term.Done():
   193  			if best == nil {
   194  				return -1, nil, term.Err()
   195  			}
   196  			colors := make(set.Ints)
   197  			for _, c := range best {
   198  				colors.Add(c)
   199  			}
   200  			return colors.Count(), best, term.Err()
   201  		default:
   202  		}
   203  	}
   204  
   205  	// Select the next node.
   206  	selector.reset(cand.colors)
   207  	vid := selector.nodes[selector.dsatur()].ID()
   208  	cand.color(vid)
   209  	// If uncolor panics, we have failed to find a
   210  	// feasible color. This should never happen.
   211  	defer cand.uncolor(vid)
   212  
   213  	// Keep the adjacent colors set as it will be
   214  	// overwritten by child recurrences.
   215  	adjColors := selector.adjColors[selector.indexOf[vid]]
   216  
   217  	// Collect all feasible existing colors plus one, remembering it.
   218  	feasible := make(set.Ints)
   219  	for _, c := range cand.colors {
   220  		if adjColors.Has(c) {
   221  			continue
   222  		}
   223  		feasible.Add(c)
   224  	}
   225  	var newCol int
   226  	for c := 0; c < ub; c++ {
   227  		if feasible.Has(c) || adjColors.Has(c) {
   228  			continue
   229  		}
   230  		feasible.Add(c)
   231  		newCol = c
   232  		break
   233  	}
   234  
   235  	// Recur over every feasible color.
   236  	for c := range feasible {
   237  		cand.colors[vid] = c
   238  		effK := k
   239  		if c == newCol {
   240  			effK++
   241  		}
   242  		// In the published algorithm, the expression max(effK, lb) < ub is
   243  		// used, but lb < ub always since it is not updated and dSaturExact
   244  		// is not called if lb == ub, and it cannot be greater.
   245  		if effK < ub {
   246  			ub, best, err = dSaturExact(term, selector, cand, effK, ub, best)
   247  			if err != nil {
   248  				return ub, best, err
   249  			}
   250  		}
   251  	}
   252  
   253  	return ub, best, nil
   254  }
   255  
   256  // maximumClique returns a maximum clique in g and its order.
   257  func maximumClique(g graph.Undirected) (k int, maxClique []graph.Node, cliques [][]graph.Node) {
   258  	cliques = topo.BronKerbosch(g)
   259  	for _, c := range topo.BronKerbosch(g) {
   260  		if len(c) > len(maxClique) {
   261  			maxClique = c
   262  		}
   263  	}
   264  	return len(maxClique), maxClique, cliques
   265  }
   266  
   267  // bestMaximumClique returns the maximum clique in g with the lowest degree into
   268  // the remainder of the graph.
   269  func bestMaximumClique(g graph.Undirected, cliques [][]graph.Node) (colors map[int64]int) {
   270  	switch len(cliques) {
   271  	case 0:
   272  		return nil
   273  	case 1:
   274  		return colorClique(cliques[0])
   275  	}
   276  
   277  	sort.Slice(cliques, func(i, j int) bool { return len(cliques[i]) > len(cliques[j]) })
   278  	maxClique := cliques[0]
   279  	minDegree := cliqueDegree(g, maxClique)
   280  	for _, c := range cliques[1:] {
   281  		if len(c) < len(maxClique) {
   282  			break
   283  		}
   284  		d := cliqueDegree(g, c)
   285  		if d < minDegree {
   286  			minDegree = d
   287  			maxClique = c
   288  		}
   289  	}
   290  
   291  	return colorClique(maxClique)
   292  }
   293  
   294  // cliqueDegree returns the degree of the clique to nodes outside the clique.
   295  func cliqueDegree(g graph.Undirected, clique []graph.Node) int {
   296  	n := make(set.Int64s)
   297  	for _, u := range clique {
   298  		to := g.From(u.ID())
   299  		for to.Next() {
   300  			n.Add(to.Node().ID())
   301  		}
   302  	}
   303  	return n.Count() - len(clique)
   304  }
   305  
   306  // colorClique returns a valid coloring for the given clique.
   307  func colorClique(clique []graph.Node) map[int64]int {
   308  	colors := make(map[int64]int, len(clique))
   309  	for c, u := range clique {
   310  		colors[u.ID()] = c
   311  	}
   312  	return colors
   313  }
   314  
   315  // Randomized returns an approximate minimal chromatic number of g and a
   316  // corresponding vertex coloring using a greedy coloring algorithm with a
   317  // random node ordering. If src is non-nil it will be used as the random
   318  // source, otherwise the global random source will be used. If a partial
   319  // coloring is provided the coloring will be consistent with that partial
   320  // coloring if possible. Otherwise Randomized will return
   321  // ErrInvalidPartialColoring.
   322  func Randomized(g graph.Undirected, partial map[int64]int, src rand.Source) (k int, colors map[int64]int, err error) {
   323  	nodes := g.Nodes()
   324  	n := nodes.Len()
   325  	if n == 0 {
   326  		return
   327  	}
   328  	partial, ok := newPartial(partial, g)
   329  	if !ok {
   330  		return -1, nil, ErrInvalidPartialColoring
   331  	}
   332  	k, colors = greedyColoringOf(g, randomize(nodes, src), partial)
   333  	return k, colors, nil
   334  }
   335  
   336  // randomize returns a graph.Node iterator that returns nodes in a random
   337  // order.
   338  func randomize(it graph.Nodes, src rand.Source) graph.Nodes {
   339  	nodes := graph.NodesOf(it)
   340  	var shuffle func(int, func(i, j int))
   341  	if src == nil {
   342  		shuffle = rand.Shuffle
   343  	} else {
   344  		shuffle = rand.New(src).Shuffle
   345  	}
   346  	shuffle(len(nodes), func(i, j int) {
   347  		nodes[i], nodes[j] = nodes[j], nodes[i]
   348  	})
   349  	return iterator.NewOrderedNodes(nodes)
   350  }
   351  
   352  // RecursiveLargestFirst returns an approximate minimal chromatic number
   353  // of g and a corresponding vertex coloring using the Recursive Largest
   354  // First coloring algorithm.
   355  // See Leighton doi:10.6028/jres.084.024 for details of the algorithm.
   356  func RecursiveLargestFirst(g graph.Undirected) (k int, colors map[int64]int) {
   357  	it := g.Nodes()
   358  	n := it.Len()
   359  	if n == 0 {
   360  		return
   361  	}
   362  	nodes := graph.NodesOf(it)
   363  	colors = make(map[int64]int)
   364  
   365  	// The names of variable here have been changed from the original PL-1
   366  	// for clarity, but the correspondence is as follows:
   367  	//  E   -> isolated
   368  	//  F   -> boundary
   369  	//  L   -> current
   370  	//  COL -> k
   371  	//  C   -> colors
   372  
   373  	// Initialize the boundary vector to the node degrees.
   374  	boundary := make([]int, len(nodes))
   375  	indexOf := make(map[int64]int)
   376  	for i, u := range nodes {
   377  		uid := u.ID()
   378  		indexOf[uid] = i
   379  		boundary[i] = g.From(uid).Len()
   380  	}
   381  	deleteFrom := func(vec []int, idx int) {
   382  		vec[idx] = -1
   383  		to := g.From(nodes[idx].ID())
   384  		for to.Next() {
   385  			vec[indexOf[to.Node().ID()]]--
   386  		}
   387  	}
   388  	isolated := make([]int, len(nodes))
   389  
   390  	// If there are any uncolored nodes, initiate the assignment of the next color.
   391  	// Incrementing color happens at the end of the loop in this implementation.
   392  	var current int
   393  	for j := 0; j < n; {
   394  		// Reinitialize the isolated vector.
   395  		copy(isolated, boundary)
   396  
   397  		// Select the node in U₁ with maximal degree in U₁.
   398  		for i := range nodes {
   399  			if boundary[i] > boundary[current] {
   400  				current = i
   401  			}
   402  		}
   403  
   404  		// Color the node just selected and continue to
   405  		// color nodes with color k until U₁ is empty.
   406  		for isolated[current] >= 0 {
   407  			// Color node and modify U₁ and U₂ accordingly.
   408  			deleteFrom(isolated, current)
   409  			deleteFrom(boundary, current)
   410  			colors[nodes[current].ID()] = k
   411  			j++
   412  			to := g.From(nodes[current].ID())
   413  			for to.Next() {
   414  				i := indexOf[to.Node().ID()]
   415  				if isolated[i] >= 0 {
   416  					deleteFrom(isolated, i)
   417  				}
   418  			}
   419  
   420  			// Find the first node in U₁, if any.
   421  			for i := range nodes {
   422  				if isolated[i] < 0 {
   423  					continue
   424  				}
   425  
   426  				// If U₁ is not empty, select the next node for coloring.
   427  				current = i
   428  				currAvail := boundary[current] - isolated[current]
   429  				for j := i; j < n; j++ {
   430  					if isolated[j] < 0 {
   431  						continue
   432  					}
   433  					nextAvail := boundary[j] - isolated[j]
   434  					switch {
   435  					case nextAvail > currAvail, nextAvail == currAvail && isolated[j] < isolated[current]:
   436  						current = j
   437  						currAvail = boundary[current] - isolated[current]
   438  					}
   439  				}
   440  				break
   441  			}
   442  		}
   443  
   444  		k++
   445  	}
   446  
   447  	return k, colors
   448  }
   449  
   450  // SanSegundo returns an approximate minimal chromatic number of g and a
   451  // corresponding vertex coloring using the PASS rule with a single run of a
   452  // greedy coloring algorithm. If a partial coloring is provided the coloring
   453  // will be consistent with that partial coloring if possible. Otherwise
   454  // SanSegundo will return ErrInvalidPartialColoring.
   455  // See San Segundo doi:10.1016/j.cor.2011.10.008 for details of the algorithm.
   456  func SanSegundo(g graph.Undirected, partial map[int64]int) (k int, colors map[int64]int, err error) {
   457  	nodes := g.Nodes()
   458  	n := nodes.Len()
   459  	if n == 0 {
   460  		return
   461  	}
   462  	partial, ok := newPartial(partial, g)
   463  	if !ok {
   464  		return -1, nil, ErrInvalidPartialColoring
   465  	}
   466  	order := bySaturationDegree(nodes, g, partial)
   467  	order.heuristic = order.pass
   468  	k, colors = greedyColoringOf(g, order, order.colors)
   469  	return k, colors, nil
   470  }
   471  
   472  // WelshPowell returns an approximate minimal chromatic number of g and a
   473  // corresponding vertex coloring using the Welsh and Powell coloring algorithm.
   474  // If a partial coloring is provided the coloring will be consistent with that
   475  // partial coloring if possible. Otherwise WelshPowell will return
   476  // ErrInvalidPartialColoring.
   477  // See Welsh and Powell doi:10.1093/comjnl/10.1.85 for details of the algorithm.
   478  func WelshPowell(g graph.Undirected, partial map[int64]int) (k int, colors map[int64]int, err error) {
   479  	nodes := g.Nodes()
   480  	n := nodes.Len()
   481  	if n == 0 {
   482  		return
   483  	}
   484  	partial, ok := newPartial(partial, g)
   485  	if !ok {
   486  		return -1, nil, ErrInvalidPartialColoring
   487  	}
   488  	k, colors = greedyColoringOf(g, byDescendingDegree(nodes, g), partial)
   489  	return k, colors, nil
   490  }
   491  
   492  // byDescendingDegree returns a graph.Node iterator that returns nodes
   493  // in order of descending degree.
   494  func byDescendingDegree(it graph.Nodes, g graph.Undirected) graph.Nodes {
   495  	nodes := graph.NodesOf(it)
   496  	n := byDescDegree{nodes: nodes, degrees: make([]int, len(nodes))}
   497  	for i, u := range nodes {
   498  		n.degrees[i] = g.From(u.ID()).Len()
   499  	}
   500  	sort.Sort(n)
   501  	return iterator.NewOrderedNodes(nodes)
   502  }
   503  
   504  // byDescDegree sorts a slice of graph.Node descending by the corresponding
   505  // value of the degrees slice.
   506  type byDescDegree struct {
   507  	nodes   []graph.Node
   508  	degrees []int
   509  }
   510  
   511  func (n byDescDegree) Len() int           { return len(n.nodes) }
   512  func (n byDescDegree) Less(i, j int) bool { return n.degrees[i] > n.degrees[j] }
   513  func (n byDescDegree) Swap(i, j int) {
   514  	n.nodes[i], n.nodes[j] = n.nodes[j], n.nodes[i]
   515  	n.degrees[i], n.degrees[j] = n.degrees[j], n.degrees[i]
   516  }
   517  
   518  // newPartial returns a new valid partial coloring is valid for g. An empty
   519  // partial coloring is valid. If the partial coloring is not valid, a nil map
   520  // is returned, otherwise a new non-nil map is returned. If the input partial
   521  // coloring is nil, a new map is created and returned.
   522  func newPartial(partial map[int64]int, g graph.Undirected) (map[int64]int, bool) {
   523  	if partial == nil {
   524  		return make(map[int64]int), true
   525  	}
   526  	for id, c := range partial {
   527  		if g.Node(id) == nil {
   528  			return nil, false
   529  		}
   530  		to := g.From(id)
   531  		for to.Next() {
   532  			if oc, ok := partial[to.Node().ID()]; ok && c == oc {
   533  				return nil, false
   534  			}
   535  		}
   536  	}
   537  	return clone(partial), true
   538  }
   539  
   540  func clone(colors map[int64]int) map[int64]int {
   541  	new := make(map[int64]int, len(colors))
   542  	for id, c := range colors {
   543  		new[id] = c
   544  	}
   545  	return new
   546  }
   547  
   548  // greedyColoringOf returns the chromatic number and a graph coloring of g
   549  // based on the sequential coloring of nodes given by order and starting from
   550  // the given partial coloring.
   551  func greedyColoringOf(g graph.Undirected, order graph.Nodes, partial map[int64]int) (k int, colors map[int64]int) {
   552  	colors = partial
   553  	constrained := false
   554  	for _, c := range colors {
   555  		if c > k {
   556  			k = c
   557  			constrained = true
   558  		}
   559  	}
   560  
   561  	// Next nodes are chosen by the specified heuristic in order.
   562  	for order.Next() {
   563  		uid := order.Node().ID()
   564  		used := colorsOf(g.From(uid), colors)
   565  		if c, ok := colors[uid]; ok {
   566  			if used.Has(c) {
   567  				return -1, nil
   568  			}
   569  			continue
   570  		}
   571  		// Color the chosen vertex with the least possible
   572  		// (lowest numbered) color.
   573  		for c := 0; c <= k+1; c++ {
   574  			if !used.Has(c) {
   575  				colors[uid] = c
   576  				if c > k {
   577  					k = c
   578  				}
   579  				break
   580  			}
   581  		}
   582  	}
   583  
   584  	if !constrained {
   585  		return k + 1, colors
   586  	}
   587  	seen := make(set.Ints)
   588  	for _, c := range colors {
   589  		seen.Add(c)
   590  	}
   591  	return seen.Count(), colors
   592  }
   593  
   594  // colorsOf returns all the colors in the coloring that are used by the
   595  // given nodes.
   596  func colorsOf(nodes graph.Nodes, coloring map[int64]int) set.Ints {
   597  	c := make(set.Ints, nodes.Len())
   598  	for nodes.Next() {
   599  		used, ok := coloring[nodes.Node().ID()]
   600  		if ok {
   601  			c.Add(used)
   602  		}
   603  	}
   604  	return c
   605  }
   606  
   607  // saturationDegreeIterator is a graph.Nodes iterator that returns nodes ordered
   608  // by decreasing saturation degree.
   609  type saturationDegreeIterator struct {
   610  	// cnt is the number of nodes that
   611  	// have been returned and curr is
   612  	// the current selection.
   613  	cnt, curr int
   614  
   615  	// heuristic determines the
   616  	// iterator's node selection
   617  	// heuristic. It can be either
   618  	// saturationDegree.dsatur or
   619  	// saturationDegree.pass.
   620  	heuristic func() int
   621  
   622  	saturationDegree
   623  }
   624  
   625  // bySaturationDegree returns a new saturationDegreeIterator that will
   626  // iterate over the node in it based on the given graph and partial coloring.
   627  // The saturationDegreeIterator holds a reference to colors allowing
   628  // greedyColoringOf to update its coloring.
   629  func bySaturationDegree(it graph.Nodes, g graph.Undirected, colors map[int64]int) *saturationDegreeIterator {
   630  	return &saturationDegreeIterator{
   631  		cnt: -1, curr: -1,
   632  		saturationDegree: newSaturationDegree(it, g, colors),
   633  	}
   634  }
   635  
   636  // Len returns the number of elements remaining in the iterator.
   637  // saturationDegreeIterator is an indeterminate iterator, so Len always
   638  // returns -1. This is required to satisfy the graph.Iterator interface.
   639  func (n *saturationDegreeIterator) Len() int { return -1 }
   640  
   641  // Next advances the iterator to the next node and returns whether
   642  // the next call to the Node method will return a valid Node.
   643  func (n *saturationDegreeIterator) Next() bool {
   644  	if uint(n.cnt)+1 < uint(len(n.nodes)) {
   645  		n.cnt++
   646  		switch n.cnt {
   647  		case 0:
   648  			max := -1
   649  			for i, d := range n.degrees {
   650  				if d > max {
   651  					max = d
   652  					n.curr = i
   653  				}
   654  			}
   655  		default:
   656  			prev := n.Node().ID()
   657  			c := n.colors[prev]
   658  			to := n.g.From(prev)
   659  			for to.Next() {
   660  				n.adjColors[n.indexOf[to.Node().ID()]].Add(c)
   661  			}
   662  
   663  			chosen := n.heuristic()
   664  			if chosen < 0 || chosen == n.curr {
   665  				return false
   666  			}
   667  			n.curr = chosen
   668  		}
   669  		return true
   670  	}
   671  	n.cnt = len(n.nodes)
   672  	return false
   673  }
   674  
   675  // Node returns the current node.
   676  func (n *saturationDegreeIterator) Node() graph.Node { return n.nodes[n.curr] }
   677  
   678  // Reset implements the graph.Iterator interface. It should not be called.
   679  func (n *saturationDegreeIterator) Reset() { panic("coloring: invalid call to Reset") }
   680  
   681  // saturationDegree is a saturation degree node choice heuristic.
   682  type saturationDegree struct {
   683  	// nodes is the set of nodes being
   684  	// iterated over.
   685  	nodes []graph.Node
   686  
   687  	// indexOf is a mapping between node
   688  	// IDs and elements of degree and
   689  	// adjColors. degrees holds the
   690  	// degree of each node and adjColors
   691  	// holds the current adjacent
   692  	// colors of each node.
   693  	indexOf   map[int64]int
   694  	degrees   []int
   695  	adjColors []set.Ints
   696  
   697  	// g and colors are the graph coloring.
   698  	// colors is held by both the iterator
   699  	// and greedyColoringOf.
   700  	g      graph.Undirected
   701  	colors map[int64]int
   702  
   703  	// work is a temporary workspace.
   704  	work []int
   705  }
   706  
   707  // newSaturationDegree returns a saturationDegree heuristic based on the
   708  // nodes in the given node iterator and graph, using the provided coloring.
   709  func newSaturationDegree(it graph.Nodes, g graph.Undirected, colors map[int64]int) saturationDegree {
   710  	nodes := graph.NodesOf(it)
   711  	sd := saturationDegree{
   712  		nodes:     nodes,
   713  		indexOf:   make(map[int64]int, len(nodes)),
   714  		degrees:   make([]int, len(nodes)),
   715  		adjColors: make([]set.Ints, len(nodes)),
   716  		g:         g,
   717  		colors:    colors,
   718  	}
   719  	for i, u := range nodes {
   720  		sd.degrees[i] = g.From(u.ID()).Len()
   721  		sd.adjColors[i] = make(set.Ints)
   722  		sd.indexOf[u.ID()] = i
   723  	}
   724  	for uid, c := range colors {
   725  		to := g.From(uid)
   726  		for to.Next() {
   727  			sd.adjColors[sd.indexOf[to.Node().ID()]].Add(c)
   728  		}
   729  	}
   730  	return sd
   731  }
   732  
   733  // reset re-initializes the saturation with the provided colors.
   734  func (sd *saturationDegree) reset(colors map[int64]int) {
   735  	sd.colors = colors
   736  	for i := range sd.nodes {
   737  		sd.adjColors[i] = make(set.Ints)
   738  	}
   739  	for uid, c := range colors {
   740  		to := sd.g.From(uid)
   741  		for to.Next() {
   742  			sd.adjColors[sd.indexOf[to.Node().ID()]].Add(c)
   743  		}
   744  	}
   745  }
   746  
   747  // dsatur implements the Dsatur heuristic from Brélaz doi:10.1145/359094.359101.
   748  func (sd *saturationDegree) dsatur() int {
   749  	maxSat, maxDeg, chosen := -1, -1, -1
   750  	for i, u := range sd.nodes {
   751  		uid := u.ID()
   752  		if _, ok := sd.colors[uid]; ok {
   753  			continue
   754  		}
   755  		s := saturationDegreeOf(uid, sd.g, sd.colors)
   756  		d := sd.degrees[i]
   757  		switch {
   758  		// Choose a vertex with a maximal saturation degree.
   759  		// If there is an equality, choose any vertex of maximal
   760  		// degree in the uncolored subgraph.
   761  		case s > maxSat, s == maxSat && d > maxDeg:
   762  			maxSat = s
   763  			maxDeg = d
   764  			chosen = i
   765  		}
   766  	}
   767  	return chosen
   768  }
   769  
   770  // pass implements the PASS heuristic from San Segundo doi:10.1016/j.cor.2011.10.008.
   771  func (sd *saturationDegree) pass() int {
   772  	maxSat, chosen := -1, -1
   773  	sd.work = sd.work[:0]
   774  	for i, u := range sd.nodes {
   775  		uid := u.ID()
   776  		if _, ok := sd.colors[uid]; ok {
   777  			continue
   778  		}
   779  		s := saturationDegreeOf(uid, sd.g, sd.colors)
   780  		switch {
   781  		case s > maxSat:
   782  			maxSat = s
   783  			sd.work = sd.work[:0]
   784  			fallthrough
   785  		case s == maxSat:
   786  			sd.work = append(sd.work, i)
   787  		}
   788  	}
   789  	maxAvail := -1
   790  	for _, vs := range sd.work {
   791  		var avail int
   792  		for _, v := range sd.work {
   793  			if v != vs {
   794  				avail += sd.same(sd.adjColors[vs], sd.adjColors[v])
   795  			}
   796  		}
   797  		switch {
   798  		case avail > maxAvail, avail == maxAvail && sd.nodes[chosen].ID() < sd.nodes[vs].ID():
   799  			maxAvail = avail
   800  			chosen = vs
   801  		}
   802  	}
   803  	return chosen
   804  }
   805  
   806  // same implements the same function from San Segundo doi:10.1016/j.cor.2011.10.008.
   807  func (sd *saturationDegree) same(vi, vj set.Ints) int {
   808  	valid := make(set.Ints)
   809  	for _, c := range sd.colors {
   810  		if !vi.Has(c) {
   811  			valid.Add(c)
   812  		}
   813  	}
   814  	for c := range vj {
   815  		valid.Remove(c)
   816  	}
   817  	return valid.Count()
   818  }
   819  
   820  // saturationDegreeOf returns the saturation degree of the node corresponding to
   821  // vid in g with the given coloring.
   822  func saturationDegreeOf(vid int64, g graph.Undirected, colors map[int64]int) int {
   823  	if _, ok := colors[vid]; ok {
   824  		panic("coloring: saturation degree not defined for colored node")
   825  	}
   826  	adjColors := make(set.Ints)
   827  	to := g.From(vid)
   828  	for to.Next() {
   829  		if c, ok := colors[to.Node().ID()]; ok {
   830  			adjColors.Add(c)
   831  		}
   832  	}
   833  	return adjColors.Count()
   834  }