Skip to content

Is2EdgeTransitive performance update #739

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

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open
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
22 changes: 11 additions & 11 deletions doc/prop.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1580,31 +1580,31 @@ false]]></Example>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="IsTwoEdgeTransitive">
<#GAPDoc Label="Is2EdgeTransitive">
<ManSection>
<Prop Name="IsTwoEdgeTransitive" Arg="digraph"/>
<Prop Name="Is2EdgeTransitive" Arg="digraph"/>
<Returns><K>true</K> or <K>false</K>.</Returns>
<Description>
If <A>digraph</A> is a digraph without multiple edges, then <C>IsTwoEdgeTransitive</C>
If <A>digraph</A> is a digraph without multiple edges, then <C>Is2EdgeTransitive</C>
returns <K>true</K> if <A>digraph</A> is 2-edge transitive, and <K>false</K>
otherwise. A digraph is <E>2-edge transitive</E> if its automorphism group
acts transitively on its 2-edges via the action
<Ref Func="OnTuplesTuples" BookName="ref"/>.
acts transitively on 2-edges via the action
<Ref Func="OnTuples" BookName="ref"/>.

A <E>2-edge</E> of a digraph is a pair of its edges, such that the range of the
first edge is equal to the source of the second edge.
A <E>2-edge</E> in a digraph is a triple (u, v, w) of distinct vertices
such that (u, v) and (v, w) are edges.
<P/>

&MUTABLE_RECOMPUTED_PROP;

<Example><![CDATA[
gap> IsTwoEdgeTransitive(CompleteDigraph(4));
gap> Is2EdgeTransitive(CompleteDigraph(4));
true
gap> IsTwoEdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1], [3, 4]]))
gap> Is2EdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 4]]));
false
gap> IsTwoEdgeTransitive(CycleDigraph(5));
gap> Is2EdgeTransitive(CycleDigraph(5));
true
gap> IsTwoEdgeTransitive(Digraph([[2], [3, 3, 3], []]));
gap> Is2EdgeTransitive(Digraph([[2], [3, 3, 3], []]));
Error, the argument <D> must be a digraph with no multiple edges,
]]></Example>
</Description>
Expand Down
1 change: 1 addition & 0 deletions doc/z-chap5.xml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
<#Include Label="IsDigraphCore">
<#Include Label="IsEdgeTransitive">
<#Include Label="IsVertexTransitive">
<#Include Label="Is2EdgeTransitive">
</Section>


Expand Down
2 changes: 1 addition & 1 deletion gap/prop.gd
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ DeclareProperty("IsMeetSemilatticeDigraph", IsDigraph);
DeclareProperty("IsPermutationDigraph", IsDigraph);
DeclareProperty("IsDistributiveLatticeDigraph", IsDigraph);
DeclareProperty("IsModularLatticeDigraph", IsDigraph);
DeclareProperty("IsTwoEdgeTransitive", IsDigraph);
DeclareProperty("Is2EdgeTransitive", IsDigraph);
DeclareSynonymAttr("IsLatticeDigraph",
IsMeetSemilatticeDigraph and IsJoinSemilatticeDigraph);
DeclareSynonymAttr("IsPreorderDigraph",
Expand Down
89 changes: 79 additions & 10 deletions gap/prop.gi
Original file line number Diff line number Diff line change
Expand Up @@ -687,25 +687,94 @@ function(D)
return LatticeDigraphEmbedding(N5, D) = fail;
end);

InstallMethod(IsTwoEdgeTransitive,
InstallMethod(Is2EdgeTransitive,
"for a digraph without multiple edges",
[IsDigraph],
function(D)
local twoEdges;

local Aut, O, I, Centers, Count, In, Out, u;
if IsMultiDigraph(D) then
ErrorNoReturn("the argument <D> must be a digraph with no multiple",
" edges,");
fi;

twoEdges := Filtered(Cartesian(DigraphEdges(D), DigraphEdges(D)),
pair -> pair[1][2] = pair[2][1]
and pair[1][1] <> pair[2][2]);
Aut := AutomorphismGroup(D);
D := DigraphRemoveLoops(D);
O := D!.OutNeighbours;
I := InNeighbours(D);
# The list Centers will store all those vertices which lie at the
# center of a 2-edge.

Centers := [];

for u in [1 .. Length(O)] do
if Length(O[u]) > 0 and Length(I[u]) > 0 then
# If u has precisely one in neighbour and out neighbour,
# we must check these are not the same vertex as then there
# would be no 2-edge centered at u.

if Length(O[u]) = 1 and Length(I[u]) = 1 then
if O[u][1] = I[u][1] then
continue;
fi;
fi;
if not IsBound(Out) then
Out := Length(O[u]);
In := Length(I[u]);
fi;
# For D to be 2-edge transitive, it must be transitive
# on 2-edge centers, so all 2-edge centers must have the
# same in-degree and same out-degree.

if Length(twoEdges) = 0 then
if Out <> Length(O[u]) or In <> Length(I[u]) then
return false;
fi;
Add(Centers, u);
fi;
od;
# If Centers is empty, D has no 2-edges so is vacuously 2-edge
# transtive.

if Length(Centers) = 0 then
return true;
else
return OrbitLength(AutomorphismGroup(D), twoEdges[1], OnTuplesTuples)
= Length(twoEdges);
fi;
# Find the number of 2-cycles at any center. We will have to subtract
# these from the total number of 2-edges as 2-cycles are not classed
# as 2-edges.

Count := 0;
for u in O[Centers[1]] do
if Centers[1] in O[u] then
Count := Count + 1;
fi;
od;

# Find a 2-edge and check if its orbit length equals the number of 2-edges.
# By this point, we know that D is likely a highly symmetric digraph,
# since all 2-edge centers share a common in and out degree
# (This is by no means a guarantee, see Frucht's graph). From testing,
# calculating the stabilizer and using the orbit-stabilizer
# theorem is usually must faster in this case, so we instead determine
# the stabilizer of a 2-edge.

for u in I[Centers[1]] do
if Position(O[Centers[1]], u) = 1 then
if Length(O[Centers[1]]) = 1 then
continue;
else
return (In * Out - Count) * Length(Centers) =
Order(Aut) / Order(Stabilizer(Aut,
[u,
Centers[1],
O[Centers[1]][2]],
OnTuples));
fi;
else
return (In * Out - Count) * Length(Centers) =
Order(Aut) / Order(Stabilizer(Aut,
[u,
Centers[1],
O[Centers[1]][1]],
OnTuples));
fi;
od;
end);
18 changes: 9 additions & 9 deletions tst/standard/prop.tst
Original file line number Diff line number Diff line change
Expand Up @@ -1679,22 +1679,22 @@ true
gap> IsEdgeTransitive(Digraph([[2], [3, 3, 3], []]));
Error, the argument <D> must be a digraph with no multiple edges,

# IsTwoEdgeTransitive
gap> IsTwoEdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1]]));
# Is2EdgeTransitive
gap> Is2EdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1]]));
true
gap> IsTwoEdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1], [3, 4]]));
gap> Is2EdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1], [3, 4]]));
false
gap> IsTwoEdgeTransitive(CompleteDigraph(4));
gap> Is2EdgeTransitive(CompleteDigraph(4));
true
gap> IsTwoEdgeTransitive(CycleDigraph(100));
gap> Is2EdgeTransitive(CycleDigraph(100));
true
gap> IsTwoEdgeTransitive(CompleteBipartiteDigraph(11, 23));
gap> Is2EdgeTransitive(CompleteBipartiteDigraph(11, 23));
false
gap> IsTwoEdgeTransitive(DigraphByEdges([[1, 2]]));
gap> Is2EdgeTransitive(DigraphByEdges([[1, 2]]));
true
gap> IsTwoEdgeTransitive(DigraphByEdges([]));
gap> Is2EdgeTransitive(DigraphByEdges([]));
true
gap> IsTwoEdgeTransitive(Digraph([[2], [3, 3, 3], []]));
gap> Is2EdgeTransitive(Digraph([[2], [3, 3, 3], []]));
Error, the argument <D> must be a digraph with no multiple edges,

# DigraphHasNoVertices and DigraphHasAVertex
Expand Down
4 changes: 2 additions & 2 deletions tst/testinstall.tst
Original file line number Diff line number Diff line change
Expand Up @@ -436,8 +436,8 @@ rec( distances := [ [ 0, 5 ], [ 5, 0 ] ],
gap> EdgeWeightedDigraphShortestPath(d, 1, 2);
[ [ 1, 2 ], [ 1 ] ]

# IsTwoEdgeTransitive
gap> IsTwoEdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1]]));
# Is2EdgeTransitive
gap> Is2EdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1]]));
true

# Issue 617: bug in DigraphRemoveEdge, wasn't removing edge labels
Expand Down
Loading