Skip to content
Open
Show file tree
Hide file tree
Changes from 5 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
2 changes: 2 additions & 0 deletions gap/prop.gd
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ DeclareProperty("IsDistributiveLatticeDigraph", IsDigraph);
DeclareProperty("IsModularLatticeDigraph", IsDigraph);
DeclareProperty("Is2EdgeTransitive", IsDigraph);
DeclareProperty("IsCograph", IsDigraph);
DeclareProperty("IsBetweenCoverAndLattice", IsDigraph);
DeclareSynonymAttr("IsLatticeDigraph",
IsMeetSemilatticeDigraph and IsJoinSemilatticeDigraph);
DeclareSynonymAttr("IsPreorderDigraph",
Expand Down Expand Up @@ -82,6 +83,7 @@ InstallTrueMethod(IsAcyclicDigraph, IsEmptyDigraph);
InstallTrueMethod(IsAcyclicDigraph, IsTournament and IsTransitiveDigraph);
InstallTrueMethod(IsAntisymmetricDigraph, IsAcyclicDigraph);
InstallTrueMethod(IsAntisymmetricDigraph, IsDigraph and IsTournament);
InstallTrueMethod(IsBetweenCoverAndLattice, IsLatticeDigraph);
InstallTrueMethod(IsBipartiteDigraph, IsCompleteBipartiteDigraph);
InstallTrueMethod(IsBipartiteDigraph, IsDigraph and IsUndirectedForest);
InstallTrueMethod(IsCompleteMultipartiteDigraph, IsCompleteBipartiteDigraph);
Expand Down
89 changes: 89 additions & 0 deletions gap/prop.gi
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,60 @@ function(D, P, U, join)
return tab;
end);

# Variant of DIGRAPHS_MeetJoinTable that does not require the input digraph
# to have all transitive edges: reachability between previously processed
# vertices is checked via the table being constructed, rather than via
# direct edge queries on the input digraph.
# Note: above descriptive comment is LLM-generated.
BindGlobal("DIGRAPHS_MeetJoinTableBetweenCover",
Comment thread
ThatOtherAndrew marked this conversation as resolved.
function(N, P, U, join)
local ord, tab, S, i, x, T, l, q, z, y;

tab := List([1 .. N], x -> []);

ord := [];
for i in [1 .. N] do
ord[P[i]] := i;
od;

S := [];

for x in P do
tab[x, x] := x;
for y in S do
T := [];
for z in U[x] do
Add(T, tab[y, z]);
od;
T := Set(T);
l := Length(T);
if l = 0 then
return fail;
fi;
q := T[l];
for i in [1 .. l - 1] do
z := T[i];
if ord[z] > ord[q] then
q := z;
fi;
od;
for z in T do
# the below conditions are the only part that
# differs from MeetJoinTable above
if join and tab[q, z] <> z then
return fail;
elif not join and tab[z, q] <> z then
return fail;
Comment on lines +132 to +137
Copy link
Copy Markdown
Collaborator

@reiniscirpons reiniscirpons Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that this is the only difference, would it be feasible to modify DIGRAPHS_MeetJoinTable to have both functionalities e.g. by adding an extra boolean parameter check_edges, which makes the DIGRAPHS_MeetJoinTable behave the same as before if set to true and otherwise make it behave like DIGRAPHS_MeetJoinTableBetweenCover?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On it! Would doing a text search for "DIGRAPHS_MeetJoinTable" be sufficient to ensure that all places affected by the function signature breaking change are covered?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I think so! It would also be nice if you could add a comment describing what each of the input parameters D, P, U, join and the new one you add is expected to be, and how using them affects the output. The DIGRAPHS_ prefix functions are for internal use only, so they don't get an official documentation entry, but it might be useful for the next person who touches the code.

fi;
od;
tab[x, y] := q;
tab[y, x] := q;
od;
Add(S, x);
od;
return tab;
end);

InstallMethod(DIGRAPHS_IsJoinSemilatticeAndJoinTable, "for a digraph",
[IsDigraph],
function(D)
Expand Down Expand Up @@ -137,6 +191,41 @@ InstallMethod(IsMeetSemilatticeDigraph, "for a digraph",
[IsDigraph],
D -> DIGRAPHS_IsMeetSemilatticeAndMeetTable(D)[1]);

InstallMethod(IsBetweenCoverAndLattice, "for a digraph",
[IsDigraph],
function(D)
local copy, order, hasse, neighbours, table;

Comment thread
ThatOtherAndrew marked this conversation as resolved.
Outdated
# 1. Topologically sort the nodes in D.
copy := DigraphRemoveLoops(DigraphMutableCopyIfMutable(D));
# ^ protect from nasty mutable side effects i think
Comment thread
ThatOtherAndrew marked this conversation as resolved.
Outdated
Comment thread
ThatOtherAndrew marked this conversation as resolved.
Outdated
order := DigraphTopologicalSort(copy);
if order = fail then
return false;
Comment thread
ThatOtherAndrew marked this conversation as resolved.
fi;

# 2. Iterate through pairs of nodes of D in topological order
# and construct a table of their meets.
hasse := DigraphTransitiveReduction(copy);
neighbours := InNeighbours(hasse);
table := DIGRAPHS_MeetJoinTableBetweenCover(
DigraphNrVertices(copy),
Reversed(order),
neighbours,
false);
if table = fail then
return false;
fi;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if IsImmutableDigraph(D) then
SetDigraphMeetTable(D, tab);
fi;

We can save the result as the meet table here, since we already did all that work to compute it. The same should be done for the join table below.

neighbours := OutNeighbours(hasse);
table := DIGRAPHS_MeetJoinTableBetweenCover(
DigraphNrVertices(copy),
order,
neighbours,
true);
return table <> fail;
Comment on lines +221 to +227
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the similarity of this line to the previous one, would it might make more sense to have two functions IsBetweenCoverAndMeetSemilattice and IsBetweenCoverAndJoinSemilattice which to this check with the meet and join table respectively and then make IsBetweenCoverAndLattice to simply return true when both IsBetweenCoverAndMeetSemilattice and IsBetweenCoverAndJoinSemilattice are true, like we do for IsLatticeDigraph.

end);

InstallImmediateMethod(IsStronglyConnectedDigraph,
IsDigraph and HasDigraphStronglyConnectedComponents, 0,
D -> Length(DigraphStronglyConnectedComponents(D).comps) = 1);
Expand Down
42 changes: 42 additions & 0 deletions tst/standard/prop.tst
Original file line number Diff line number Diff line change
Expand Up @@ -1427,6 +1427,48 @@ false
gap> IsLatticeDigraph(gr);
false

# IsBetweenCoverAndLattice
gap> IsBetweenCoverAndLattice(Digraph([]));
true
gap> IsBetweenCoverAndLattice(Digraph([[]]));
true
gap> IsBetweenCoverAndLattice(Digraph([[1]]));
true
gap> IsBetweenCoverAndLattice(ChainDigraph(5));
true
gap> IsBetweenCoverAndLattice(DigraphReflexiveTransitiveClosure(ChainDigraph(5)));
true
gap> D := Digraph([[2, 3], [4], [4], []]);
<immutable digraph with 4 vertices, 4 edges>
gap> IsLatticeDigraph(D);
false
gap> IsBetweenCoverAndLattice(D);
true
gap> D := Digraph([[2, 3, 4], [4], [4], []]);
<immutable digraph with 4 vertices, 5 edges>
gap> IsBetweenCoverAndLattice(D);
true
gap> D := DigraphReflexiveTransitiveClosure(Digraph([[2, 3], [4], [4], []]));
<immutable preorder digraph with 4 vertices, 9 edges>
gap> IsLatticeDigraph(D);
true
gap> IsBetweenCoverAndLattice(D);
true
gap> D := Digraph([[3, 4], [3, 4], [5], [5], []]);
<immutable digraph with 5 vertices, 6 edges>
gap> IsBetweenCoverAndLattice(D);
false
gap> IsBetweenCoverAndLattice(CycleDigraph(3));
false
gap> IsBetweenCoverAndLattice(Digraph([[], []]));
false
gap> D := Digraph(IsMutable, [[2, 3], [4], [4], []]);
<mutable digraph with 4 vertices, 4 edges>
gap> IsBetweenCoverAndLattice(D);
true
gap> D;
<mutable digraph with 4 vertices, 4 edges>

# IsDistributiveLatticeDigraph
gap> D := Digraph([[11, 10], [], [2], [2], [3], [4, 3], [6, 5], [7], [7],
> [8], [9, 8]]);
Expand Down
Loading