-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Zykov and Christofides Algorithms for Chromatic Number #491
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -369,6 +369,192 @@ function(D) | |
end | ||
); | ||
|
||
BindGlobal("DIGRAPHS_ChromaticNumberZykov", | ||
function(D) | ||
local nr, ZykovReduce, chrom; | ||
nr := DigraphNrVertices(D); | ||
# Recursive function call | ||
ZykovReduce := function(D) | ||
local nr, D_contract, vertices, v, x, y, i, j, adjacent; | ||
nr := DigraphNrVertices(D); | ||
# Update upper bound if possible. | ||
chrom := Minimum(nr, chrom); | ||
# Leaf nodes are either complete graphs or cliques that have size equal to | ||
# the current upper bound. The chromatic number is then the smallest clique | ||
# found. | ||
# Cliques finder arguments: | ||
# digraph = D - The graph | ||
# hook = fail - hook is not required | ||
# user_param = [] - user_param is a list as hook is fail | ||
# limit = 1 - We only need one clique | ||
# include = exclude = [] - We check all vertices | ||
# max = false - This clique need not be maximal | ||
# size = chrom - We want a clique the size of our upper bound | ||
# reps = true - As we only care about the existence of the clique, | ||
# we can instead search for representatives which is more efficient. | ||
if not IsCompleteDigraph(D) and IsEmpty(CliquesFinder(D, fail, [], 1, [], | ||
[], false, chrom, | ||
true)) then | ||
# Sort vertices by degree, so that higher degree vertices are picked first | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is already implemented in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for letting me know about |
||
# Picking higher degree vertices will make it more likely a clique will | ||
# form in one of the modified graphs, which will terminate the recursion. | ||
vertices := DigraphWelshPowellOrder(D); | ||
# Get the adjacency function | ||
adjacent := DigraphAdjacencyFunction(D); | ||
# Choose two non-adjacent vertices x, y | ||
for i in [1 .. nr] do | ||
x := vertices[i]; | ||
# Search for the first vertex not adjacent to all others | ||
# This is guaranteed to exist as D is not the complete graph. | ||
if OutDegreeOfVertex(D, x) < nr - 1 then | ||
# Now search for a non-adjacent vertex, prioritising higher degree ones | ||
for j in [i + 1 .. nr] do | ||
y := vertices[j]; | ||
if not adjacent(x, y) then | ||
break; | ||
fi; | ||
od; | ||
break; | ||
fi; | ||
od; | ||
Assert(1, x <> 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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't you use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looking through the manual I can't seem to find any reference to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see now there is an open pull request for |
||
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 <D> is at least 3 and at most nr | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you possibly add a comment to this line about what it is that the
CliquesFinder
function is looking for here?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add some additional explanation for the
CliqueFinder
call.