Skip to content

Commit 4e191fa

Browse files
Is2EdgeTransitive performance update (#739)
* Change to GAP stable-4.14 in CI * Add HasPseudoSimilarVertices no docs * Fixed syntax * fixed syntax * Add HasPSVs * Is2EdgeTransitive overhaul using Orbit-Stabiliser Theorem * Added support for digraphs with loops * Linting * More linting * Edited Documentation * Edited Documentation again * Once more rewritten Is2EdgeTransitive, this time to avoid looping through all triples of vertices, and instead checks center vertices of 2-edges * lint * Added more comments to prop.gi * Fix trailing whitespace * Added IsTwoEdgeTransitive as synonym for Is2EdgeTransitive * lint * Removed spurious files and added what happens when the argument of Is2EdgeTransitive has multiple edges to doc * fixed typo in doc
1 parent f762447 commit 4e191fa

6 files changed

Lines changed: 105 additions & 34 deletions

File tree

doc/prop.xml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,31 +1589,31 @@ false]]></Example>
15891589
</ManSection>
15901590
<#/GAPDoc>
15911591

1592-
<#GAPDoc Label="IsTwoEdgeTransitive">
1592+
<#GAPDoc Label="Is2EdgeTransitive">
15931593
<ManSection>
1594-
<Prop Name="IsTwoEdgeTransitive" Arg="digraph"/>
1594+
<Prop Name="Is2EdgeTransitive" Arg="digraph"/>
15951595
<Returns><K>true</K> or <K>false</K>.</Returns>
15961596
<Description>
1597-
If <A>digraph</A> is a digraph without multiple edges, then <C>IsTwoEdgeTransitive</C>
1597+
If <A>digraph</A> is a digraph without multiple edges, then <C>Is2EdgeTransitive</C>
15981598
returns <K>true</K> if <A>digraph</A> is 2-edge transitive, and <K>false</K>
1599-
otherwise. A digraph is <E>2-edge transitive</E> if its automorphism group
1600-
acts transitively on its 2-edges via the action
1601-
<Ref Func="OnTuplesTuples" BookName="ref"/>.
1599+
otherwise. If <A>digraph</A> has multiple edges, then <C>Is2EdgeTransitive</C> returns an error.
16021600

1603-
A <E>2-edge</E> of a digraph is a pair of its edges, such that the range of the
1604-
first edge is equal to the source of the second edge.
1601+
A digraph is <E>2-edge transitive</E> if its automorphism group
1602+
acts transitively on 2-edges via the action
1603+
<Ref Func="OnTuples" BookName="ref"/>. A <E>2-edge</E> in a digraph is a triple (u, v, w) of distinct vertices
1604+
such that (u, v) and (v, w) are edges.
16051605
<P/>
16061606

16071607
&MUTABLE_RECOMPUTED_PROP;
16081608

16091609
<Example><![CDATA[
1610-
gap> IsTwoEdgeTransitive(CompleteDigraph(4));
1610+
gap> Is2EdgeTransitive(CompleteDigraph(4));
16111611
true
1612-
gap> IsTwoEdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1], [3, 4]]))
1612+
gap> Is2EdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 4]]));
16131613
false
1614-
gap> IsTwoEdgeTransitive(CycleDigraph(5));
1614+
gap> Is2EdgeTransitive(CycleDigraph(5));
16151615
true
1616-
gap> IsTwoEdgeTransitive(Digraph([[2], [3, 3, 3], []]));
1616+
gap> Is2EdgeTransitive(Digraph([[2], [3, 3, 3], []]));
16171617
Error, the argument <D> must be a digraph with no multiple edges,
16181618
]]></Example>
16191619
</Description>

doc/z-chap5.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
<#Include Label="IsDigraphCore">
7979
<#Include Label="IsEdgeTransitive">
8080
<#Include Label="IsVertexTransitive">
81+
<#Include Label="Is2EdgeTransitive">
8182
</Section>
8283

8384

gap/prop.gd

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ DeclareProperty("IsMeetSemilatticeDigraph", IsDigraph);
5353
DeclareProperty("IsPermutationDigraph", IsDigraph);
5454
DeclareProperty("IsDistributiveLatticeDigraph", IsDigraph);
5555
DeclareProperty("IsModularLatticeDigraph", IsDigraph);
56-
DeclareProperty("IsTwoEdgeTransitive", IsDigraph);
56+
DeclareProperty("Is2EdgeTransitive", IsDigraph);
5757
DeclareSynonymAttr("IsLatticeDigraph",
5858
IsMeetSemilatticeDigraph and IsJoinSemilatticeDigraph);
5959
DeclareSynonymAttr("IsPreorderDigraph",
@@ -70,6 +70,7 @@ DeclareSynonymAttr("IsEquivalenceDigraph",
7070
DeclareSynonymAttr("IsAntiSymmetricDigraph", IsAntisymmetricDigraph);
7171
DeclareSynonymAttr("IsNullDigraph", IsEmptyDigraph);
7272
DeclareSynonymAttr("IsQuasiorderDigraph", IsPreorderDigraph);
73+
DeclareSynonymAttr("IsTwoEdgeTransitive", Is2EdgeTransitive);
7374

7475
DeclareOperation("DIGRAPHS_IsJoinSemilatticeAndJoinTable", [IsDigraph]);
7576
DeclareOperation("DIGRAPHS_IsMeetSemilatticeAndMeetTable", [IsDigraph]);

gap/prop.gi

Lines changed: 79 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -693,25 +693,94 @@ function(D)
693693
return LatticeDigraphEmbedding(N5, D) = fail;
694694
end);
695695

696-
InstallMethod(IsTwoEdgeTransitive,
696+
InstallMethod(Is2EdgeTransitive,
697697
"for a digraph without multiple edges",
698698
[IsDigraph],
699699
function(D)
700-
local twoEdges;
701-
700+
local Aut, O, I, Centers, Count, In, Out, u;
702701
if IsMultiDigraph(D) then
703702
ErrorNoReturn("the argument <D> must be a digraph with no multiple",
704703
" edges,");
705704
fi;
706705

707-
twoEdges := Filtered(Cartesian(DigraphEdges(D), DigraphEdges(D)),
708-
pair -> pair[1][2] = pair[2][1]
709-
and pair[1][1] <> pair[2][2]);
706+
Aut := AutomorphismGroup(D);
707+
D := DigraphRemoveLoops(D);
708+
O := D!.OutNeighbours;
709+
I := InNeighbours(D);
710+
# The list Centers will store all those vertices which lie at the
711+
# center of a 2-edge.
712+
713+
Centers := [];
714+
715+
for u in [1 .. Length(O)] do
716+
if Length(O[u]) > 0 and Length(I[u]) > 0 then
717+
# If u has precisely one in neighbour and out neighbour,
718+
# we must check these are not the same vertex as then there
719+
# would be no 2-edge centered at u.
720+
721+
if Length(O[u]) = 1 and Length(I[u]) = 1 then
722+
if O[u][1] = I[u][1] then
723+
continue;
724+
fi;
725+
fi;
726+
if not IsBound(Out) then
727+
Out := Length(O[u]);
728+
In := Length(I[u]);
729+
fi;
730+
# For D to be 2-edge transitive, it must be transitive
731+
# on 2-edge centers, so all 2-edge centers must have the
732+
# same in-degree and same out-degree.
710733

711-
if Length(twoEdges) = 0 then
734+
if Out <> Length(O[u]) or In <> Length(I[u]) then
735+
return false;
736+
fi;
737+
Add(Centers, u);
738+
fi;
739+
od;
740+
# If Centers is empty, D has no 2-edges so is vacuously 2-edge
741+
# transtive.
742+
743+
if Length(Centers) = 0 then
712744
return true;
713-
else
714-
return OrbitLength(AutomorphismGroup(D), twoEdges[1], OnTuplesTuples)
715-
= Length(twoEdges);
716745
fi;
746+
# Find the number of 2-cycles at any center. We will have to subtract
747+
# these from the total number of 2-edges as 2-cycles are not classed
748+
# as 2-edges.
749+
750+
Count := 0;
751+
for u in O[Centers[1]] do
752+
if Centers[1] in O[u] then
753+
Count := Count + 1;
754+
fi;
755+
od;
756+
757+
# Find a 2-edge and check if its orbit length equals the number of 2-edges.
758+
# By this point, we know that D is likely a highly symmetric digraph,
759+
# since all 2-edge centers share a common in and out degree
760+
# (This is by no means a guarantee, see Frucht's graph). From testing,
761+
# calculating the stabilizer and using the orbit-stabilizer
762+
# theorem is usually must faster in this case, so we instead determine
763+
# the stabilizer of a 2-edge.
764+
765+
for u in I[Centers[1]] do
766+
if Position(O[Centers[1]], u) = 1 then
767+
if Length(O[Centers[1]]) = 1 then
768+
continue;
769+
else
770+
return (In * Out - Count) * Length(Centers) =
771+
Order(Aut) / Order(Stabilizer(Aut,
772+
[u,
773+
Centers[1],
774+
O[Centers[1]][2]],
775+
OnTuples));
776+
fi;
777+
else
778+
return (In * Out - Count) * Length(Centers) =
779+
Order(Aut) / Order(Stabilizer(Aut,
780+
[u,
781+
Centers[1],
782+
O[Centers[1]][1]],
783+
OnTuples));
784+
fi;
785+
od;
717786
end);

tst/standard/prop.tst

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1738,22 +1738,22 @@ true
17381738
gap> IsEdgeTransitive(Digraph([[2], [3, 3, 3], []]));
17391739
Error, the argument <D> must be a digraph with no multiple edges,
17401740

1741-
# IsTwoEdgeTransitive
1742-
gap> IsTwoEdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1]]));
1741+
# Is2EdgeTransitive
1742+
gap> Is2EdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1]]));
17431743
true
1744-
gap> IsTwoEdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1], [3, 4]]));
1744+
gap> Is2EdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1], [3, 4]]));
17451745
false
1746-
gap> IsTwoEdgeTransitive(CompleteDigraph(4));
1746+
gap> Is2EdgeTransitive(CompleteDigraph(4));
17471747
true
1748-
gap> IsTwoEdgeTransitive(CycleDigraph(100));
1748+
gap> Is2EdgeTransitive(CycleDigraph(100));
17491749
true
1750-
gap> IsTwoEdgeTransitive(CompleteBipartiteDigraph(11, 23));
1750+
gap> Is2EdgeTransitive(CompleteBipartiteDigraph(11, 23));
17511751
false
1752-
gap> IsTwoEdgeTransitive(DigraphByEdges([[1, 2]]));
1752+
gap> Is2EdgeTransitive(DigraphByEdges([[1, 2]]));
17531753
true
1754-
gap> IsTwoEdgeTransitive(DigraphByEdges([]));
1754+
gap> Is2EdgeTransitive(DigraphByEdges([]));
17551755
true
1756-
gap> IsTwoEdgeTransitive(Digraph([[2], [3, 3, 3], []]));
1756+
gap> Is2EdgeTransitive(Digraph([[2], [3, 3, 3], []]));
17571757
Error, the argument <D> must be a digraph with no multiple edges,
17581758

17591759
# DigraphHasNoVertices and DigraphHasAVertex

tst/testinstall.tst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,8 +440,8 @@ rec( distances := [ [ 0, 5 ], [ 5, 0 ] ],
440440
gap> EdgeWeightedDigraphShortestPath(d, 1, 2);
441441
[ [ 1, 2 ], [ 1 ] ]
442442
443-
# IsTwoEdgeTransitive
444-
gap> IsTwoEdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1]]));
443+
# Is2EdgeTransitive
444+
gap> Is2EdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1]]));
445445
true
446446
447447
# Issue 617: bug in DigraphRemoveEdge, wasn't removing edge labels

0 commit comments

Comments
 (0)