diff --git a/doc/attr.xml b/doc/attr.xml index 0aeec90ca..8f0ccb755 100644 --- a/doc/attr.xml +++ b/doc/attr.xml @@ -1441,6 +1441,10 @@ gap> DigraphLoops(D); byskov - Byskov's Algorithm + zykov - Zykov's Algorithm + + christofides - Christofides's Algorithm + y, "x and y must be different"); + # Colour the vertex contraction. + # A contraction of a graph effectively merges two non adjacent vertices + # into a single new vertex with the edges merged. + # We merge y into x, keeping x. + + # TODO Use DigraphContractEdge once it is implemented. + D_contract := DigraphMutableCopy(D); + for v in vertices do + # Iterate over all vertices that are not x or y + if v = x or v = y then + continue; + fi; + # Add any edge that involves y, but not already x to avoid duplication. + if adjacent(v, y) and not adjacent(v, x) then + DigraphAddEdge(D_contract, x, v); + DigraphAddEdge(D_contract, v, x); + fi; + od; + DigraphRemoveVertex(D_contract, y); + ZykovReduce(D_contract); + # Colour the edge addition + # This just adds symmetric edges between x and y; + DigraphAddEdge(D, [x, y]); + DigraphAddEdge(D, [y, x]); + ZykovReduce(D); + # Undo changes to the graph + DigraphRemoveEdge(D, [x, y]); + DigraphRemoveEdge(D, [y, x]); + fi; + end; + # Algorithm requires an undirected graph without multiple edges. + D := DigraphMutableCopy(D); + D := DigraphRemoveAllMultipleEdges(D); + D := DigraphSymmetricClosure(D); + # Use greedy colouring as an upper bound + chrom := RankOfTransformation(DigraphGreedyColouring(D), nr); + ZykovReduce(D); + return chrom; +end +); + +BindGlobal("DIGRAPHS_ChromaticNumberChristofides", +function(D) + local nr, I, n, T, b, unprocessed, i, v_without_t, j, u, min_occurrences, + cur_occurrences, chrom, colouring, stack, vertices; + + nr := DigraphNrVertices(D); + vertices := List(DigraphVertices(D)); + # Initialise the required variables. + # Calculate all maximal independent sets of D. + I := DigraphMaximalIndependentSets(D); + # Convert each MIS into a BList + I := List(I, i -> BlistList(vertices, i)); + # Upper bound for chromatic number. + chrom := nr; + # Set of vertices of D not in the current subgraph at level n. + T := ListWithIdenticalEntries(nr, false); + # Current search level of the subgraph tree. + n := 0; + # The maximal independent sets of V \ T at level n. + b := [ListWithIdenticalEntries(nr, false)]; + # Number of unprocessed MIS's of V \ T from level 1 to n + unprocessed := ListWithIdenticalEntries(nr, 0); + # Would be jth colour class of the chromatic colouring of G. + colouring := List([1 .. nr], i -> BlistList(vertices, [i])); + # Stores current unprocessed MIS's of V \ T at level 1 to level n + stack := []; + # Now perform the search. + repeat + # Step 2 + if n < chrom then + # Step 3 + # If V = T then we've reached a null subgraph + if SizeBlist(T) = nr then + chrom := n; + SubtractBlist(T, b[n + 1]); + for i in [1 .. chrom] do + colouring[i] := b[i]; + # TODO set colouring attribute + od; + else + # Step 4 + # Compute the maximal independent sets of V \ T + v_without_t := DIGRAPHS_MaximalIndependentSetsSubtractedSet(I, T, + infinity); + # Step 5 + # Pick u in V \ T such that u is in the fewest maximal independent sets. + u := -1; + min_occurrences := infinity; + # Flip T to get V \ T + FlipBlist(T); + # Convert to list to iterate over the vertices. + for i in ListBlist(vertices, T) do + # Count how many times this vertex appears in a MIS + cur_occurrences := Number(v_without_t, j -> j[i]); + if cur_occurrences < min_occurrences then + min_occurrences := cur_occurrences; + u := i; + fi; + od; + # Revert changes to T + FlipBlist(T); + Assert(1, u <> -1, "Vertex must be picked"); + # Remove maximal independent sets not containing u. + v_without_t := Filtered(v_without_t, x -> x[u]); + # Add these MISs to the stack + Append(stack, v_without_t); + # Search has moved one level deeper + n := n + 1; + unprocessed[n] := Length(v_without_t); + fi; + else + # if n >= g then T = T \ b[n] + # This exceeds the current best bound, so stop search. + SubtractBlist(T, b[n + 1]); + fi; + # Step 6 + while n <> 0 do + # step 7 + if unprocessed[n] = 0 then + n := n - 1; + SubtractBlist(T, b[n + 1]); + else + # Step 8 + # take an element from the top of the stack + i := Remove(stack); + unprocessed[n] := unprocessed[n] - 1; + b[n + 1] := i; + UniteBlist(T, i); + break; + fi; + od; + until n = 0; + return chrom; +end +); + InstallMethod(ChromaticNumber, "for a digraph by out-neighbours", [IsDigraphByOutNeighboursRep], function(D) @@ -392,6 +578,10 @@ function(D) return DIGRAPHS_ChromaticNumberLawler(D); elif ValueOption("byskov") <> fail then return DIGRAPHS_ChromaticNumberByskov(D); + elif ValueOption("zykov") <> fail then + return DIGRAPHS_ChromaticNumberZykov(D); + elif ValueOption("christofides") <> fail then + return DIGRAPHS_ChromaticNumberChristofides(D); fi; # The chromatic number of is at least 3 and at most nr diff --git a/tst/standard/attr.tst b/tst/standard/attr.tst index 1dc47d0b5..f2d59e5b9 100644 --- a/tst/standard/attr.tst +++ b/tst/standard/attr.tst @@ -1662,6 +1662,118 @@ Error, the argument must be a digraph with no loops, gap> DIGRAPHS_UnderThreeColourable(EmptyDigraph(0)); 0 +# Test ChromaticNumber Zykov +gap> ChromaticNumber(NullDigraph(10) : zykov); +1 +gap> ChromaticNumber(CompleteDigraph(10) : zykov); +10 +gap> ChromaticNumber(CompleteBipartiteDigraph(5, 5) : zykov); +2 +gap> ChromaticNumber(DigraphRemoveEdge(CompleteDigraph(10), [1, 2]) : zykov); +10 +gap> ChromaticNumber(Digraph([[4, 8], [6, 10], [9], [2, 3, 9], [], +> [3], [4], [6], [], [5, 7]]) : zykov); +3 +gap> ChromaticNumber(DigraphDisjointUnion(CompleteDigraph(1), +> Digraph([[2], [4], [1, 2], [3]])) : zykov); +3 +gap> ChromaticNumber(DigraphDisjointUnion(CompleteDigraph(1), +> Digraph([[2], [4], [1, 2], [3], [1, 2, 3]])) : zykov); +4 +gap> gr := Digraph([[2, 3, 4], [3], [], []]); + +gap> ChromaticNumber(gr : zykov); +3 +gap> ChromaticNumber(EmptyDigraph(0) : zykov); +0 +gap> gr := CompleteDigraph(4);; +gap> gr := DigraphAddVertex(gr);; +gap> ChromaticNumber(gr : zykov); +4 +gap> gr := Digraph([[2, 4, 7, 3], [3, 5, 8, 1], [1, 6, 9, 2], +> [5, 7, 1, 6], [6, 8, 2, 4], [4, 9, 3, 5], [8, 1, 4, 9], [9, 2, 5, 7], +> [7, 3, 6, 8]]);; +gap> ChromaticNumber(gr : zykov); +3 +gap> gr := DigraphSymmetricClosure(ChainDigraph(5)); + +gap> ChromaticNumber(gr : zykov); +2 +gap> gr := DigraphFromGraph6String("KmKk~K??G@_@"); + +gap> ChromaticNumber(gr : zykov); +4 +gap> gr := CycleDigraph(7); + +gap> ChromaticNumber(gr : zykov); +3 +gap> ChromaticNumber(gr : zykov); +3 +gap> ChromaticNumber(gr : zykov); +3 +gap> a := DigraphRemoveEdges(CompleteDigraph(50), [[1, 2], [2, 1]]);; +gap> b := DigraphAddVertex(a);; +gap> ChromaticNumber(a : zykov); +49 +gap> ChromaticNumber(b : zykov); +49 + +# Test ChromaticNumber Christofides +gap> ChromaticNumber(NullDigraph(10) : christofides); +1 +gap> ChromaticNumber(CompleteDigraph(10) : christofides); +10 +gap> ChromaticNumber(CompleteBipartiteDigraph(5, 5) : christofides); +2 +gap> ChromaticNumber(DigraphRemoveEdge(CompleteDigraph(10), [1, 2]) : christofides); +10 +gap> ChromaticNumber(Digraph([[4, 8], [6, 10], [9], [2, 3, 9], [], +> [3], [4], [6], [], [5, 7]]) : christofides); +3 +gap> ChromaticNumber(DigraphDisjointUnion(CompleteDigraph(1), +> Digraph([[2], [4], [1, 2], [3]])) : christofides); +3 +gap> ChromaticNumber(DigraphDisjointUnion(CompleteDigraph(1), +> Digraph([[2], [4], [1, 2], [3], [1, 2, 3]])) : christofides); +4 +gap> gr := Digraph([[2, 3, 4], [3], [], []]); + +gap> ChromaticNumber(gr : christofides); +3 +gap> ChromaticNumber(EmptyDigraph(0) : christofides); +0 +gap> gr := CompleteDigraph(4);; +gap> gr := DigraphAddVertex(gr);; +gap> ChromaticNumber(gr : christofides); +4 +gap> gr := Digraph([[2, 4, 7, 3], [3, 5, 8, 1], [1, 6, 9, 2], +> [5, 7, 1, 6], [6, 8, 2, 4], [4, 9, 3, 5], [8, 1, 4, 9], [9, 2, 5, 7], +> [7, 3, 6, 8]]);; +gap> ChromaticNumber(gr : christofides); +3 +gap> gr := DigraphSymmetricClosure(ChainDigraph(5)); + +gap> ChromaticNumber(gr : christofides); +2 +gap> gr := DigraphFromGraph6String("KmKk~K??G@_@"); + +gap> ChromaticNumber(gr : christofides); +4 +gap> gr := CycleDigraph(7); + +gap> ChromaticNumber(gr : christofides); +3 +gap> ChromaticNumber(gr : christofides); +3 +gap> ChromaticNumber(gr : christofides); +3 +gap> a := DigraphRemoveEdges(CompleteDigraph(50), [[1, 2], [2, 1]]);; +gap> b := DigraphAddVertex(a);; +gap> ChromaticNumber(a : christofides); +49 +gap> ChromaticNumber(b : christofides); +49 + # DegreeMatrix gap> gr := Digraph([[2, 3, 4], [2, 5], [1, 5, 4], [1], [1, 1, 2, 4]]);; gap> DegreeMatrix(gr);