Skip to content
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 DigraphAllChordlessCycles #679

Merged
merged 5 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions doc/attr.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1374,6 +1374,45 @@ gap> DigraphLongestSimpleCircuit(D);
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphAllChordlessCycles">
<ManSection>
<Attr Name="DigraphAllChordlessCycles" Arg="digraph"/>
<Returns>A list of lists of vertices.</Returns>
<Description>
If <A>digraph</A> is a digraph, then <C>DigraphAllChordlessCycles</C>
returns a list of the <E>chordless cycles</E> in <A>digraph</A>. <P/>

A chordless cycle <M>C</M> is a undirected simple circuit (see Section <Ref Subsect="Definitions" Style="Number" /> )
where each pair of vertices in <M>C</M> are not connected by an edge not in <M>C</M>.
Here, cycles of length two are ignored.<P/>

For a digraph without multiple edges, a simple circuit is uniquely
determined by its subsequence of vertices. However this is not the case for
a multidigraph. The attribute <C>DigraphAllChordlessCycles</C> ignores
multiple edges, and identifies a simple circuit using only its subsequence
of vertices. See Section <Ref Subsect="DigraphAllSimpleCircuits" Style="Number" /> for more details.<P/>

This method uses the algorithms described in <Cite Key="US14"/>.<P/>
<Example><![CDATA[
gap> D := ChainDigraph(10);;
gap> DigraphAllChordlessCycles(D);
[ ]
gap> D := Digraph([[1, 1]]);
<immutable multidigraph with 1 vertex, 2 edges>
gap> DigraphAllChordlessCycles(D);
[ ]
gap> D := CycleDigraph(3);;
gap> DigraphAllChordlessCycles(D);
[ [ 2, 1, 3 ] ]
gap> D := CompleteDigraph(4);
<immutable complete digraph with 4 vertices>
gap> DigraphAllChordlessCycles(D);
[ [ 2, 1, 3 ], [ 2, 1, 4 ], [ 3, 1, 4 ], [ 3, 2, 4 ] ]
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="HamiltonianPath">
<ManSection>
<Attr Name="HamiltonianPath" Arg="digraph"/>
Expand Down
10 changes: 10 additions & 0 deletions doc/digraphs.bib
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,13 @@ @article{Bys2002
Journal = {BRICS Report Series},
Doi = {10.7146/brics.v9i45.21760}
}

@InProceedings{US14,
author="Uno, Takeaki and Satoh, Hiroko",
title="An Efficient Algorithm for Enumerating Chordless Cycles and Chordless Paths",
booktitle="Discovery Science",
year="2014",
publisher="Springer International Publishing",
pages="313--324",
isbn="978-3-319-11812-3"
}
1 change: 1 addition & 0 deletions doc/z-chap4.xml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
<#Include Label="IteratorOfPaths">
<#Include Label="DigraphAllSimpleCircuits">
<#Include Label="DigraphLongestSimpleCircuit">
<#Include Label="DigraphAllChordlessCycles">
<#Include Label="DigraphLayers">
<#Include Label="DigraphDegeneracy">
<#Include Label="DigraphDegeneracyOrdering">
Expand Down
1 change: 1 addition & 0 deletions gap/attr.gd
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ DeclareAttribute("DigraphAbsorptionExpectedSteps", IsDigraph);

DeclareAttribute("DigraphAllSimpleCircuits", IsDigraph);
DeclareAttribute("DigraphLongestSimpleCircuit", IsDigraph);
DeclareAttribute("DigraphAllChordlessCycles", IsDigraph);
DeclareAttribute("HamiltonianPath", IsDigraph);
DeclareAttribute("DigraphPeriod", IsDigraph);
DeclareAttribute("DigraphLoops", IsDigraph);
Expand Down
99 changes: 99 additions & 0 deletions gap/attr.gi
Original file line number Diff line number Diff line change
Expand Up @@ -1500,6 +1500,105 @@ function(D)
return Concatenation(loops, out);
end);

# Compute all chordless cycles for a given symmetric digraph
# Algorithm based on https://arxiv.org/pdf/1404.7610
InstallMethod(DigraphAllChordlessCycles, "for a digraph",
[IsDigraph],
function(D)
local BlockNeighbours, UnblockNeighbours,
Triplets, CCExtension, digraph, temp, T, C, blocked, triple;

if IsEmptyDigraph(D) then
return [];
fi;

BlockNeighbours := function(digraph, v, blocked)
local u;
for u in OutNeighboursOfVertex(digraph, v) do
blocked[u] := blocked[u] + 1;
od;
return blocked;
end;

UnblockNeighbours := function(digraph, v, blocked)
local u;
for u in OutNeighboursOfVertex(digraph, v) do
if blocked[u] > 0 then
blocked[u] := blocked[u] - 1;
fi;
od;
return blocked;
end;

# Computes all possible triplets
Triplets := function(digraph)
local T, C, u, pair, x, y, labels;
T := [];
C := [];
for u in DigraphVertices(digraph) do
for pair in Combinations(OutNeighboursOfVertex(digraph, u), 2) do
x := pair[1];
y := pair[2];
labels := DigraphVertexLabels(digraph);
if labels[u] < labels[x] and labels[x] < labels[y] then
if not IsDigraphEdge(digraph, x, y) then
Add(T, [x, u, y]);
else
Add(C, [x, u, y]);
fi;
elif labels[u] < labels[y] and labels[y] < labels[x] then
if not IsDigraphEdge(digraph, x, y) then
Add(T, [y, u, x]);
else
Add(C, [y, u, x]);
fi;
fi;
od;
od;
return [T, C];
end;

# Extends a given chordless path if possible
CCExtension := function(digraph, path, C, key, blocked)
local v, extendedPath, data;
blocked := BlockNeighbours(digraph, Last(path), blocked);
for v in OutNeighboursOfVertex(digraph, Last(path)) do
if DigraphVertexLabel(digraph, v) > key and blocked[v] = 1 then
extendedPath := Concatenation(path, [v]);
if IsDigraphEdge(digraph, v, First(path)) then
Add(C, extendedPath);
else
data := CCExtension(digraph, extendedPath, C, key, blocked);
C := data[1];
blocked := data[2];
fi;
fi;
od;
blocked := UnblockNeighbours(digraph, Last(path), blocked);
return [C, blocked];
end;

digraph := DigraphSymmetricClosure(DigraphRemoveLoops(
DigraphRemoveAllMultipleEdges(DigraphMutableCopyIfMutable(D))));

SetDigraphVertexLabels(digraph,
Reversed(DigraphDegeneracyOrdering(digraph)));
temp := Triplets(digraph);
T := temp[1];
C := temp[2];
blocked := List(DigraphVertices(digraph), i -> 0);
while T <> [] do
triple := Remove(T);
blocked := BlockNeighbours(digraph, triple[2], blocked);
temp := CCExtension(digraph, triple, C,
DigraphVertexLabel(digraph, triple[2]), blocked);
C := temp[1];
blocked := temp[2];
blocked := UnblockNeighbours(digraph, triple[2], blocked);
od;
return C;
end);

# The following method 'DIGRAPHS_Bipartite' was originally written by Isabella
# Scott and then modified by FLS.
# It is the backend to IsBipartiteDigraph, Bicomponents, and DigraphColouring
Expand Down
19 changes: 19 additions & 0 deletions tst/standard/attr.tst
Original file line number Diff line number Diff line change
Expand Up @@ -948,6 +948,25 @@ gap> gr := Digraph([[3, 6, 7], [3, 6, 8], [1, 2, 3, 6, 7, 8],
gap> Length(DigraphAllSimpleCircuits(gr));
259

# DigraphAllChordlessCycles
gap> gr := Digraph([]);;
gap> DigraphAllChordlessCycles(gr);
[ ]
gap> gr := ChainDigraph(4);;
gap> DigraphAllChordlessCycles(gr);
[ ]
gap> D := CycleDigraph(3);;
gap> DigraphAllChordlessCycles(D);
[ [ 2, 1, 3 ] ]
gap> D := CompleteDigraph(4);;
gap> DigraphAllChordlessCycles(D);
[ [ 2, 1, 3 ], [ 2, 1, 4 ], [ 3, 1, 4 ], [ 3, 2, 4 ] ]
gap> D := Digraph([[2, 4, 5], [3, 6], [4, 7], [8], [6, 8], [7], [8], []]);;
gap> DigraphAllChordlessCycles(D);
[ [ 6, 5, 8, 7 ], [ 3, 4, 8, 5, 6, 2 ], [ 3, 4, 8, 7 ], [ 1, 4, 8, 5 ],
[ 1, 4, 8, 7, 6, 2 ], [ 1, 4, 3, 2 ], [ 1, 4, 3, 7, 6, 5 ], [ 3, 2, 6, 7 ],
[ 2, 1, 5, 6 ], [ 2, 1, 5, 8, 7, 3 ] ]

# DigraphLongestSimpleCircuit
gap> gr := Digraph([]);;
gap> DigraphLongestSimpleCircuit(gr);
Expand Down
Loading