From 9d1c20d26314791b5a83c221bcb4cb247a07d531 Mon Sep 17 00:00:00 2001 From: Frankie Gillis Date: Wed, 5 Feb 2025 18:04:42 +0000 Subject: [PATCH 01/15] Change to GAP stable-4.14 in CI --- .github/workflows/config_options.yml | 4 ++-- .github/workflows/os.yml | 8 ++++---- .github/workflows/ubuntu.yml | 1 + .github/workflows/valgrind.yml | 4 ++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/config_options.yml b/.github/workflows/config_options.yml index 9d87afffd..1ef1f4b66 100644 --- a/.github/workflows/config_options.yml +++ b/.github/workflows/config_options.yml @@ -56,7 +56,7 @@ jobs: with: GAP_PKGS_TO_CLONE: NautyTracesInterface digraphs/graphviz GAP_PKGS_TO_BUILD: io orb datastructures grape NautyTracesInterface - GAPBRANCH: stable-4.13 + GAPBRANCH: stable-4.14 - name: Build Digraphs . . . uses: gap-actions/build-pkg@v1 with: @@ -95,7 +95,7 @@ jobs: with: GAP_PKGS_TO_CLONE: NautyTracesInterface digraphs/graphviz GAP_PKGS_TO_BUILD: io orb datastructures grape NautyTracesInterface - GAPBRANCH: stable-4.13 + GAPBRANCH: stable-4.14 - name: Build Digraphs . . . uses: gap-actions/build-pkg@v1 with: diff --git a/.github/workflows/os.yml b/.github/workflows/os.yml index 1a1eba4cd..e387d7baa 100644 --- a/.github/workflows/os.yml +++ b/.github/workflows/os.yml @@ -20,7 +20,7 @@ concurrency: jobs: test-unix: - name: ${{ matrix.os }}${{ matrix.ABI }} / GAP stable-4.13 + name: ${{ matrix.os }}${{ matrix.ABI }} / GAP stable-4.14 runs-on: ${{ matrix.os }}-latest strategy: fail-fast: false @@ -47,7 +47,7 @@ jobs: with: GAP_PKGS_TO_CLONE: ${{ matrix.pkgs-to-clone }} GAP_PKGS_TO_BUILD: ${{ matrix.pkgs-to-build }} - GAPBRANCH: stable-4.13 + GAPBRANCH: stable-4.14 ABI: ${{ matrix.ABI }} - name: Build Digraphs . . . uses: gap-actions/build-pkg@v1 @@ -83,7 +83,7 @@ jobs: GAP_TESTFILE: tst/github_actions/extreme.g test-cygwin: - name: cygwin / GAP stable-4.13 + name: cygwin / GAP stable-4.14 runs-on: windows-latest env: CHERE_INVOKING: 1 @@ -94,7 +94,7 @@ jobs: with: GAP_PKGS_TO_CLONE: NautyTracesInterface digraphs/graphviz GAP_PKGS_TO_BUILD: io orb datastructures grape NautyTracesInterface - GAPBRANCH: stable-4.13 + GAPBRANCH: stable-4.14 - uses: gap-actions/build-pkg@cygwin-v1 - name: Install digraphs-lib . . . run: | diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 3ba7c2b88..48b98e386 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -30,6 +30,7 @@ jobs: - stable-4.11 - stable-4.12 - stable-4.13 + - stable-4.14 only-needed: - true - false diff --git a/.github/workflows/valgrind.yml b/.github/workflows/valgrind.yml index 40227c018..f431b677e 100644 --- a/.github/workflows/valgrind.yml +++ b/.github/workflows/valgrind.yml @@ -20,7 +20,7 @@ concurrency: jobs: test-valgrind: - name: Ubuntu / GAP stable-4.13 / valgrind + name: Ubuntu / GAP stable-4.14 / valgrind runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -33,7 +33,7 @@ jobs: with: GAP_PKGS_TO_CLONE: NautyTracesInterface digraphs/graphviz GAP_PKGS_TO_BUILD: io orb datastructures grape NautyTracesInterface - GAPBRANCH: stable-4.13 + GAPBRANCH: stable-4.14 CONFIGFLAGS: --enable-valgrind - name: Build Digraphs . . . uses: gap-actions/build-pkg@v1 From 4cc0df540943b473bf2f04d10b5f4f4a2943e03c Mon Sep 17 00:00:00 2001 From: Frankie Gillis Date: Sun, 2 Mar 2025 15:31:16 +0000 Subject: [PATCH 02/15] Add HasPseudoSimilarVertices no docs --- gap/prop.gd | 1 + gap/prop.gi | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/gap/prop.gd b/gap/prop.gd index ee3ab4453..3850bc503 100644 --- a/gap/prop.gd +++ b/gap/prop.gd @@ -53,6 +53,7 @@ DeclareProperty("IsPermutationDigraph", IsDigraph); DeclareProperty("IsDistributiveLatticeDigraph", IsDigraph); DeclareProperty("IsModularLatticeDigraph", IsDigraph); DeclareProperty("IsTwoEdgeTransitive", IsDigraph); +DeclareProperty("HasPseudoSimilarVertices", IsDigraph); DeclareSynonymAttr("IsLatticeDigraph", IsMeetSemilatticeDigraph and IsJoinSemilatticeDigraph); DeclareSynonymAttr("IsPreorderDigraph", diff --git a/gap/prop.gi b/gap/prop.gi index e519535b2..a915e0428 100644 --- a/gap/prop.gi +++ b/gap/prop.gi @@ -699,7 +699,8 @@ function(D) fi; twoEdges := Filtered(Cartesian(DigraphEdges(D), DigraphEdges(D)), - pair -> pair[1][2] = pair[2][1] + + pair -> pair[1][2] = pair[2][1] and pair[1][1] <> pair[2][2]); if Length(twoEdges) = 0 then @@ -709,3 +710,23 @@ function(D) = Length(twoEdges); fi; end); + +InstallMethod(HasPseudoSimilarVertices, +"for a digraph without loops or multiple edges", +[IsDigraph], +function(D) + local u,v; + + for u in DigraphVertices(D) do + for v in DigraphVertices(D) do + if IsIsomorphicDigraph(DigraphRemoveVertex(D,u), + DigraphRemoveVertex(D,v)) + then + if v not in Orbit(AutomorphismGroup(D,u)) then + return true; + fi; + fi; + od; + od; +return false; +end); From f05eaf3de2f05014e0983f668384d1f305a868b2 Mon Sep 17 00:00:00 2001 From: Frankie Gillis Date: Sun, 2 Mar 2025 15:32:36 +0000 Subject: [PATCH 03/15] Fixed syntax --- gap/prop.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/prop.gi b/gap/prop.gi index a915e0428..378ea23b2 100644 --- a/gap/prop.gi +++ b/gap/prop.gi @@ -722,7 +722,7 @@ function(D) if IsIsomorphicDigraph(DigraphRemoveVertex(D,u), DigraphRemoveVertex(D,v)) then - if v not in Orbit(AutomorphismGroup(D,u)) then + if not v in Orbit(AutomorphismGroup(D,u)) then return true; fi; fi; From 5c5f5e8387aa5ff83e5d674a6b3e2ee860897e94 Mon Sep 17 00:00:00 2001 From: Frankie Gillis Date: Sun, 2 Mar 2025 15:38:57 +0000 Subject: [PATCH 04/15] fixed syntax --- gap/prop.gi | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gap/prop.gi b/gap/prop.gi index 378ea23b2..c19f4c7e6 100644 --- a/gap/prop.gi +++ b/gap/prop.gi @@ -715,18 +715,18 @@ InstallMethod(HasPseudoSimilarVertices, "for a digraph without loops or multiple edges", [IsDigraph], function(D) - local u,v; + local u, v; for u in DigraphVertices(D) do for v in DigraphVertices(D) do - if IsIsomorphicDigraph(DigraphRemoveVertex(D,u), - DigraphRemoveVertex(D,v)) + if IsIsomorphicDigraph(DigraphRemoveVertex(D, u), + DigraphRemoveVertex(D, v)) then - if not v in Orbit(AutomorphismGroup(D,u)) then + if not v in Orbit(AutomorphismGroup(D), u) then return true; fi; fi; od; od; -return false; + return false; end); From 81a7065fab1729a18821d1bfdc4146c8479e6d0e Mon Sep 17 00:00:00 2001 From: Frankie Gillis Date: Wed, 26 Mar 2025 14:23:10 +0000 Subject: [PATCH 05/15] Add HasPSVs --- doc/z-chap5.xml | 1 + gap/prop.gd | 1 - gap/prop.gi | 72 +++++++++++++++++++++++++------------------------ 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/doc/z-chap5.xml b/doc/z-chap5.xml index c12da5479..247f23626 100644 --- a/doc/z-chap5.xml +++ b/doc/z-chap5.xml @@ -76,6 +76,7 @@ <#Include Label="IsDigraphCore"> <#Include Label="IsEdgeTransitive"> <#Include Label="IsVertexTransitive"> + <#Include Label="IsTwoEdgeTransitive"> diff --git a/gap/prop.gd b/gap/prop.gd index 3850bc503..ee3ab4453 100644 --- a/gap/prop.gd +++ b/gap/prop.gd @@ -53,7 +53,6 @@ DeclareProperty("IsPermutationDigraph", IsDigraph); DeclareProperty("IsDistributiveLatticeDigraph", IsDigraph); DeclareProperty("IsModularLatticeDigraph", IsDigraph); DeclareProperty("IsTwoEdgeTransitive", IsDigraph); -DeclareProperty("HasPseudoSimilarVertices", IsDigraph); DeclareSynonymAttr("IsLatticeDigraph", IsMeetSemilatticeDigraph and IsJoinSemilatticeDigraph); DeclareSynonymAttr("IsPreorderDigraph", diff --git a/gap/prop.gi b/gap/prop.gi index c19f4c7e6..efd167a59 100644 --- a/gap/prop.gi +++ b/gap/prop.gi @@ -691,42 +691,44 @@ InstallMethod(IsTwoEdgeTransitive, "for a digraph without multiple edges", [IsDigraph], function(D) - local twoEdges; - - if IsMultiDigraph(D) then - ErrorNoReturn("the argument 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]); - - if Length(twoEdges) = 0 then + local v, u, w, N, twoEdgeOrbit, aut, numTwoEdges, len; + + aut := AutomorphismGroup(D); + N := OutNeighbours(D); + + if Size(aut) > 10 ^ 3 then + numTwoEdges := 0; + for u in [1 .. Length(N)] do + for v in N[u] do + for w in N[v] do + if u <> w then + numTwoEdges := numTwoEdges + 1; + if IsBound(len) then + if numTwoEdges > len then + return false; + fi; + else + len := Order(aut) / Order(Stabilizer(aut, [u, v, w], OnTuples)); + fi; + fi; + od; + od; + od; return true; else - return OrbitLength(AutomorphismGroup(D), twoEdges[1], OnTuplesTuples) - = Length(twoEdges); - fi; -end); - -InstallMethod(HasPseudoSimilarVertices, -"for a digraph without loops or multiple edges", -[IsDigraph], -function(D) - local u, v; - - for u in DigraphVertices(D) do - for v in DigraphVertices(D) do - if IsIsomorphicDigraph(DigraphRemoveVertex(D, u), - DigraphRemoveVertex(D, v)) - then - if not v in Orbit(AutomorphismGroup(D), u) then - return true; - fi; - fi; + for u in [1 .. Length(N)] do + for v in N[u] do + for w in N[v] do + if u <> w then + if not IsBound(twoEdgeOrbit) then + twoEdgeOrbit := Orbit(AutomorphismGroup(D), [u, v, w], OnTuples); + elif IsBound(twoEdgeOrbit) and not [u, v, w] in twoEdgeOrbit then + return false; + fi; + fi; + od; + od; od; - od; - return false; + return true; + fi; end); From d3dac89ebfc2a9ee2a405be55a0c63d0ec76c344 Mon Sep 17 00:00:00 2001 From: Frankie Gillis Date: Wed, 26 Mar 2025 14:46:21 +0000 Subject: [PATCH 06/15] Is2EdgeTransitive overhaul using Orbit-Stabiliser Theorem --- doc/prop.xml | 17 ++++++++--------- doc/z-chap5.xml | 2 +- gap/prop.gd | 2 +- gap/prop.gi | 27 +++++++++++++++++---------- tst/standard/prop.tst | 18 +++++++++--------- tst/testinstall.tst | 4 ++-- 6 files changed, 38 insertions(+), 32 deletions(-) diff --git a/doc/prop.xml b/doc/prop.xml index 5ea727270..989b2edd0 100644 --- a/doc/prop.xml +++ b/doc/prop.xml @@ -1580,31 +1580,30 @@ false]]> <#/GAPDoc> -<#GAPDoc Label="IsTwoEdgeTransitive"> +<#GAPDoc Label="Is2EdgeTransitive"> - + true or false. - If digraph is a digraph without multiple edges, then IsTwoEdgeTransitive + If digraph is a digraph without multiple edges, then Is2EdgeTransitive returns true if digraph is 2-edge transitive, and false otherwise. A digraph is 2-edge transitive if its automorphism group acts transitively on its 2-edges via the action . - A 2-edge 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 2-edge in a digraph is a triple (u, v, w) of vertices such that, such that (u, v) and (v, w) are both edges.

&MUTABLE_RECOMPUTED_PROP; 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, 1], [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 must be a digraph with no multiple edges, ]]> diff --git a/doc/z-chap5.xml b/doc/z-chap5.xml index 247f23626..a9c3107f8 100644 --- a/doc/z-chap5.xml +++ b/doc/z-chap5.xml @@ -76,7 +76,7 @@ <#Include Label="IsDigraphCore"> <#Include Label="IsEdgeTransitive"> <#Include Label="IsVertexTransitive"> - <#Include Label="IsTwoEdgeTransitive"> + <#Include Label="Is2EdgeTransitive"> diff --git a/gap/prop.gd b/gap/prop.gd index ee3ab4453..a25712a08 100644 --- a/gap/prop.gd +++ b/gap/prop.gd @@ -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", diff --git a/gap/prop.gi b/gap/prop.gi index efd167a59..e4bca33ee 100644 --- a/gap/prop.gi +++ b/gap/prop.gi @@ -687,20 +687,27 @@ function(D) return LatticeDigraphEmbedding(N5, D) = fail; end); -InstallMethod(IsTwoEdgeTransitive, -"for a digraph without multiple edges", +InstallMethod(Is2EdgeTransitive, +"for a digraph without loops or multiple edges", [IsDigraph], function(D) - local v, u, w, N, twoEdgeOrbit, aut, numTwoEdges, len; + local v, u, w, OutNeighboursD, twoEdgeOrbit, aut, numTwoEdges, len; + + if IsMultiDigraph(D) then + ErrorNoReturn("the argument must be a digraph with no multiple", + " edges,"); + elif DigraphHasLoops(D) then + ErrorNoReturn("the argument must be a digraph without loops,"); + fi; aut := AutomorphismGroup(D); - N := OutNeighbours(D); + OutNeighboursD := OutNeighbours(D); if Size(aut) > 10 ^ 3 then numTwoEdges := 0; - for u in [1 .. Length(N)] do - for v in N[u] do - for w in N[v] do + for u in [1 .. Length(OutNeighboursD)] do + for v in OutNeighboursD[u] do + for w in OutNeighboursD[v] do if u <> w then numTwoEdges := numTwoEdges + 1; if IsBound(len) then @@ -716,9 +723,9 @@ function(D) od; return true; else - for u in [1 .. Length(N)] do - for v in N[u] do - for w in N[v] do + for u in [1 .. Length(OutNeighboursD)] do + for v in OutNeighboursD[u] do + for w in OutNeighboursD[v] do if u <> w then if not IsBound(twoEdgeOrbit) then twoEdgeOrbit := Orbit(AutomorphismGroup(D), [u, v, w], OnTuples); diff --git a/tst/standard/prop.tst b/tst/standard/prop.tst index b459e4ee3..503ca8dbb 100644 --- a/tst/standard/prop.tst +++ b/tst/standard/prop.tst @@ -1679,22 +1679,22 @@ true gap> IsEdgeTransitive(Digraph([[2], [3, 3, 3], []])); Error, the argument 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 must be a digraph with no multiple edges, # DigraphHasNoVertices and DigraphHasAVertex diff --git a/tst/testinstall.tst b/tst/testinstall.tst index 36a7e9c06..0f5f15ba1 100644 --- a/tst/testinstall.tst +++ b/tst/testinstall.tst @@ -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 From 51a3664b38bfa9b6ee95595b1133c33dc249c058 Mon Sep 17 00:00:00 2001 From: Frankie Gillis Date: Wed, 26 Mar 2025 15:30:55 +0000 Subject: [PATCH 07/15] Added support for digraphs with loops --- doc/prop.xml | 3 ++- gap/prop.gi | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/prop.xml b/doc/prop.xml index 989b2edd0..c7cd37fe2 100644 --- a/doc/prop.xml +++ b/doc/prop.xml @@ -1591,7 +1591,8 @@ false]]> acts transitively on its 2-edges via the action . - A 2-edge in a digraph is a triple (u, v, w) of vertices such that, such that (u, v) and (v, w) are both edges. + A 2-edge in a digraph is a triple (u, v, w) of vertices, + such that (u, v) and (v, w) are both edges and u is not equal to w.

&MUTABLE_RECOMPUTED_PROP; diff --git a/gap/prop.gi b/gap/prop.gi index e4bca33ee..f38ebc7af 100644 --- a/gap/prop.gi +++ b/gap/prop.gi @@ -688,7 +688,7 @@ function(D) end); InstallMethod(Is2EdgeTransitive, -"for a digraph without loops or multiple edges", +"for a digraph without multiple edges", [IsDigraph], function(D) local v, u, w, OutNeighboursD, twoEdgeOrbit, aut, numTwoEdges, len; @@ -696,8 +696,6 @@ function(D) if IsMultiDigraph(D) then ErrorNoReturn("the argument must be a digraph with no multiple", " edges,"); - elif DigraphHasLoops(D) then - ErrorNoReturn("the argument must be a digraph without loops,"); fi; aut := AutomorphismGroup(D); From c9f28eff2361b2b02fb32fdf0b0a047103237693 Mon Sep 17 00:00:00 2001 From: Frankie Gillis Date: Wed, 26 Mar 2025 15:56:03 +0000 Subject: [PATCH 08/15] Linting --- doc/prop.xml | 2 +- gap/prop.gi | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/prop.xml b/doc/prop.xml index c7cd37fe2..664d0a767 100644 --- a/doc/prop.xml +++ b/doc/prop.xml @@ -1600,7 +1600,7 @@ false]]> Is2EdgeTransitive(CompleteDigraph(4)); true -gap> Is2EdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1], [3, 4]])) +gap> Is2EdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1], [3, 4]])); false gap> Is2EdgeTransitive(CycleDigraph(5)); true diff --git a/gap/prop.gi b/gap/prop.gi index f38ebc7af..67b131e27 100644 --- a/gap/prop.gi +++ b/gap/prop.gi @@ -692,7 +692,7 @@ InstallMethod(Is2EdgeTransitive, [IsDigraph], function(D) local v, u, w, OutNeighboursD, twoEdgeOrbit, aut, numTwoEdges, len; - + if IsMultiDigraph(D) then ErrorNoReturn("the argument must be a digraph with no multiple", " edges,"); @@ -712,7 +712,7 @@ function(D) if numTwoEdges > len then return false; fi; - else + else len := Order(aut) / Order(Stabilizer(aut, [u, v, w], OnTuples)); fi; fi; From 35033ece53077777bdcf23d4b2ba82dacefec8a9 Mon Sep 17 00:00:00 2001 From: Frankie Gillis Date: Wed, 26 Mar 2025 16:13:51 +0000 Subject: [PATCH 09/15] More linting --- doc/prop.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/prop.xml b/doc/prop.xml index 664d0a767..3ab79d840 100644 --- a/doc/prop.xml +++ b/doc/prop.xml @@ -1600,7 +1600,8 @@ false]]> Is2EdgeTransitive(CompleteDigraph(4)); true -gap> Is2EdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1], [3, 4]])); +gap> Is2EdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1], + [3, 4]])); false gap> Is2EdgeTransitive(CycleDigraph(5)); true From 02a088cab663bdad85ded6165580ed094a3a52ec Mon Sep 17 00:00:00 2001 From: Frankie Gillis Date: Wed, 26 Mar 2025 16:24:44 +0000 Subject: [PATCH 10/15] Edited Documentation --- doc/prop.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/prop.xml b/doc/prop.xml index 3ab79d840..9c148266a 100644 --- a/doc/prop.xml +++ b/doc/prop.xml @@ -1588,7 +1588,7 @@ false]]> If digraph is a digraph without multiple edges, then Is2EdgeTransitive returns true if digraph is 2-edge transitive, and false otherwise. A digraph is 2-edge transitive if its automorphism group - acts transitively on its 2-edges via the action + acts transitively on 2-edges via the action . A 2-edge in a digraph is a triple (u, v, w) of vertices, From e1eb03efeb196576b3c6b7f0e2e411a814ddaf79 Mon Sep 17 00:00:00 2001 From: Frankie Gillis Date: Wed, 26 Mar 2025 16:35:29 +0000 Subject: [PATCH 11/15] Edited Documentation again --- doc/prop.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/prop.xml b/doc/prop.xml index 9c148266a..f171a04fb 100644 --- a/doc/prop.xml +++ b/doc/prop.xml @@ -1600,8 +1600,7 @@ false]]> Is2EdgeTransitive(CompleteDigraph(4)); true -gap> Is2EdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 1], - [3, 4]])); +gap> Is2EdgeTransitive(DigraphByEdges([[1, 2], [2, 3], [3, 4]])); false gap> Is2EdgeTransitive(CycleDigraph(5)); true From bc3d5572c1084056b34b7a61ecc3e924a0826b05 Mon Sep 17 00:00:00 2001 From: Frankie Gillis Date: Sat, 26 Apr 2025 14:39:53 +0100 Subject: [PATCH 12/15] Once more rewritten Is2EdgeTransitive, this time to avoid looping through all triples of vertices, and instead checks center vertices of 2-edges --- doc/prop.xml | 6 +-- gap/prop.gi | 102 ++++++++++++++++++++++++++++++++------------------- 2 files changed, 67 insertions(+), 41 deletions(-) diff --git a/doc/prop.xml b/doc/prop.xml index f171a04fb..ef90cd68c 100644 --- a/doc/prop.xml +++ b/doc/prop.xml @@ -1589,10 +1589,10 @@ false]]> returns true if digraph is 2-edge transitive, and false otherwise. A digraph is 2-edge transitive if its automorphism group acts transitively on 2-edges via the action - . + . - A 2-edge in a digraph is a triple (u, v, w) of vertices, - such that (u, v) and (v, w) are both edges and u is not equal to w. + A 2-edge in a digraph is a triple (u, v, w) of disctinct vertices + such that (u, v) and (v, w) are edges.

&MUTABLE_RECOMPUTED_PROP; diff --git a/gap/prop.gi b/gap/prop.gi index 67b131e27..df16643cd 100644 --- a/gap/prop.gi +++ b/gap/prop.gi @@ -691,49 +691,75 @@ InstallMethod(Is2EdgeTransitive, "for a digraph without multiple edges", [IsDigraph], function(D) - local v, u, w, OutNeighboursD, twoEdgeOrbit, aut, numTwoEdges, len; - + local Aut, O, I, Centers, Count, In, Out, u, v, w; if IsMultiDigraph(D) then ErrorNoReturn("the argument must be a digraph with no multiple", " edges,"); fi; - aut := AutomorphismGroup(D); - OutNeighboursD := OutNeighbours(D); - - if Size(aut) > 10 ^ 3 then - numTwoEdges := 0; - for u in [1 .. Length(OutNeighboursD)] do - for v in OutNeighboursD[u] do - for w in OutNeighboursD[v] do - if u <> w then - numTwoEdges := numTwoEdges + 1; - if IsBound(len) then - if numTwoEdges > len then - return false; - fi; - else - len := Order(aut) / Order(Stabilizer(aut, [u, v, w], OnTuples)); - fi; - fi; - od; - od; - od; - return true; - else - for u in [1 .. Length(OutNeighboursD)] do - for v in OutNeighboursD[u] do - for w in OutNeighboursD[v] do - if u <> w then - if not IsBound(twoEdgeOrbit) then - twoEdgeOrbit := Orbit(AutomorphismGroup(D), [u, v, w], OnTuples); - elif IsBound(twoEdgeOrbit) and not [u, v, w] in twoEdgeOrbit then - return false; - fi; - fi; - od; - od; - od; + Aut := AutomorphismGroup(D); + D := DigraphRemoveLoops(D); + O := D!.OutNeighbours; + I := InNeighbours(D); + Centers := []; + + for u in [1 .. Length(O)] do + if Length(O[u]) > 0 and Length(I[u]) > 0 then + #Centre must not be part of a lone pair + 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; + #Check that centers have the same in degree + #and out degree + if Out <> Length(O[u]) or In <> Length(I[u]) then + return false; + fi; + Add(Centers, u); + fi; + od; + + #If centers in empty that D is vacuously 2-edge transitive + if Length(Centers) = 0 then return true; fi; + + #Find the number of 2-cycles at a center + Count := 0; + for v in O[Centers[1]] do + if Centers[1] in O[v] then + Count := Count + 1; + fi; + od; + + #Find a 2-edge and check if its orbit length equals the number of 2-edges. + 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); + + + From e62fc7e9e5bb059fcc9ec163c9550790d24dd38f Mon Sep 17 00:00:00 2001 From: Frankie Gillis Date: Sat, 26 Apr 2025 14:47:42 +0100 Subject: [PATCH 13/15] lint --- doc/prop.xml | 2 +- gap/prop.gi | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/prop.xml b/doc/prop.xml index ef90cd68c..11af93010 100644 --- a/doc/prop.xml +++ b/doc/prop.xml @@ -1591,7 +1591,7 @@ false]]> acts transitively on 2-edges via the action . - A 2-edge in a digraph is a triple (u, v, w) of disctinct vertices + A 2-edge in a digraph is a triple (u, v, w) of distinct vertices such that (u, v) and (v, w) are edges.

diff --git a/gap/prop.gi b/gap/prop.gi index df16643cd..ba005e381 100644 --- a/gap/prop.gi +++ b/gap/prop.gi @@ -691,13 +691,13 @@ InstallMethod(Is2EdgeTransitive, "for a digraph without multiple edges", [IsDigraph], function(D) - local Aut, O, I, Centers, Count, In, Out, u, v, w; + local Aut, O, I, Centers, Count, In, Out, u; if IsMultiDigraph(D) then ErrorNoReturn("the argument must be a digraph with no multiple", " edges,"); fi; - Aut := AutomorphismGroup(D); + Aut := AutomorphismGroup(D); D := DigraphRemoveLoops(D); O := D!.OutNeighbours; I := InNeighbours(D); @@ -706,6 +706,7 @@ function(D) for u in [1 .. Length(O)] do if Length(O[u]) > 0 and Length(I[u]) > 0 then #Centre must not be part of a lone pair + if Length(O[u]) = 1 and Length(I[u]) = 1 then if O[u][1] = I[u][1] then continue; @@ -717,27 +718,29 @@ function(D) fi; #Check that centers have the same in degree #and out degree + if Out <> Length(O[u]) or In <> Length(I[u]) then return false; fi; Add(Centers, u); fi; od; - #If centers in empty that D is vacuously 2-edge transitive + if Length(Centers) = 0 then return true; fi; - #Find the number of 2-cycles at a center + Count := 0; - for v in O[Centers[1]] do - if Centers[1] in O[v] then + 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. + for u in I[Centers[1]] do if Position(O[Centers[1]], u) = 1 then if Length(O[Centers[1]]) = 1 then @@ -760,6 +763,3 @@ function(D) fi; od; end); - - - From 141408188a9496aab0477ce647185da3e339dc01 Mon Sep 17 00:00:00 2001 From: Frankie Gillis Date: Sat, 26 Apr 2025 15:00:27 +0100 Subject: [PATCH 14/15] Added more comments to prop.gi --- gap/prop.gi | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/gap/prop.gi b/gap/prop.gi index ba005e381..e33160847 100644 --- a/gap/prop.gi +++ b/gap/prop.gi @@ -701,23 +701,29 @@ function(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 - #Centre must not be part of a lone pair + # If u has precisly 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; fi; if not IsBound(Out) then Out := Length(O[u]); In := Length(I[u]); fi; - #Check that centers have the same in degree - #and out degree + # 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 Out <> Length(O[u]) or In <> Length(I[u]) then return false; @@ -725,12 +731,15 @@ function(D) Add(Centers, u); fi; od; - #If centers in empty that D is vacuously 2-edge transitive + # If Centers is empty, D has no 2-edges so is vacuously 2-edge + # transtive. if Length(Centers) = 0 then return true; fi; - #Find the number of 2-cycles at a center + # 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 @@ -739,7 +748,13 @@ function(D) fi; od; - #Find a 2-edge and check if its orbit length equals the number of 2-edges. + # 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 From 733cc5f846d22920e7051a5cc875c1ff1ccfca5e Mon Sep 17 00:00:00 2001 From: Frankie Gillis Date: Sat, 26 Apr 2025 15:03:10 +0100 Subject: [PATCH 15/15] Fix trailing whitespace --- gap/prop.gi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gap/prop.gi b/gap/prop.gi index e33160847..22ee67fae 100644 --- a/gap/prop.gi +++ b/gap/prop.gi @@ -708,7 +708,7 @@ function(D) for u in [1 .. Length(O)] do if Length(O[u]) > 0 and Length(I[u]) > 0 then - # If u has precisly one in neighbour and out neighbour, + # 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. @@ -750,8 +750,8 @@ function(D) # 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, + # 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.