Skip to content

Commit 079bc7a

Browse files
committed
Unify OrbitalGraphs with _BTKit.getOrbitalList
This way, _BTKit.getOrbitalList can be removed from the BacktrackKit package, and BacktrackKit can rely on the OrbitalGraphs package instead. This reduces code duplication and gives further motivation to improve the OrbitalGraphs package.
1 parent e19b02f commit 079bc7a

File tree

4 files changed

+74
-30
lines changed

4 files changed

+74
-30
lines changed

gap/OrbitalGraphs.gd

+2-2
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ DeclareOperation("OrbitalGraphs", [IsPermGroup, IsHomogeneousList]);
6767
#! gap> D8 := Group([ (1,2,3,4), (2,4) ]);; StructureDescription(D8);
6868
#! "D8"
6969
#! gap> OrbitalGraphs(D8);
70-
#! [ <self-paired orbital graph of D8 on 4 vertices with base-pair (1,3), 4 arcs>
70+
#! [ <self-paired orbital graph of D8 on 4 vertices with base-pair (1,2), 8 arcs>
7171
#! , <self-paired orbital graph of D8 on 4 vertices
72-
#! with base-pair (1,2), 8 arcs> ]
72+
#! with base-pair (1,3), 4 arcs> ]
7373
#! @EndExampleSession
7474
DeclareOperation("OrbitalGraphs", [IsPermGroup, IsInt]);
7575

gap/OrbitalGraphs.gi

+67-23
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ end);
3030
InstallMethod(OrbitalGraphs, "for a permutation group and a homogeneous list",
3131
[IsPermGroup, IsHomogeneousList],
3232
function(G, points)
33-
local orb, orbitsG, iorb, graph, graphlist, val, p, i, orbsizes, D,
33+
local orb, orbitsG, iorb, graph, graphlist, val, p, i, orbsizes, D, cutoff,
34+
biggestOrbit, shouldSkipOneLargeOrbit, allowLoopyGraphs, search,
3435
orbpos, innerorblist, orbitsizes, orbreps, fillRepElts, maxval, moved;
3536

3637
if IsEmpty(points) then
@@ -48,6 +49,15 @@ function(G, points)
4849
fi;
4950
moved := Intersection(points, MovedPoints(G));
5051

52+
# Optimisation from BacktrackKit
53+
# Warning: in the future, if we wish to allow supporting orbital graphs
54+
# with loops, and choosing base points that are allowed to be fixed, then
55+
# this would mean that a trivial group could have some orbital graphs to
56+
# return, and so this optimisation would be invalid.
57+
if IsTrivial(G) then
58+
return [];
59+
fi;
60+
5161
fillRepElts := function(G, orb)
5262
local val, g, reps, buildorb, gens;
5363
reps := [];
@@ -65,49 +75,83 @@ function(G, points)
6575
return reps;
6676
end;
6777

68-
orbitsG := Orbits(G, moved);
78+
# Option `cutoff`:
79+
# Have a limit for the number of edges that an orbital graph that this
80+
# function will create. The default is infinity.
81+
if IsPosInt(ValueOption("cutoff")) then
82+
cutoff := ValueOption("cutoff");
83+
else
84+
cutoff := infinity;
85+
fi;
6986

70-
# FIXME: Currently unused
71-
orbsizes := [];
72-
# FIXME: Currently unused
73-
orbpos := [];
87+
88+
# Option `search`:
89+
# If `true`, then OrbitalGraphs will not create some orbital graphs
90+
# that are useless from the point of view of a backtrack search algorithm.
91+
search := ValueOption("search") = true;
92+
93+
# Option `skipone`
94+
# If `true`, then OrbitalGraphs will not create one of the orbital graphs
95+
# that has the largest possible number of edges. In a backtrack search,
96+
# one such orbital graph can be ignored without losing anything.
97+
shouldSkipOneLargeOrbit := search or ValueOption("skipone") = true;
98+
99+
# Make sure that the orbits of G are stably sorted, so that the resulting
100+
# list of orbital graphs for a group always comes in the same order,
101+
# with the same base pairs.
102+
orbitsG := Set(Orbits(G, moved), Set);
74103

75104
# Efficently store size of orbits of values
105+
orbsizes := [];
106+
orbpos := [];
76107
for orb in [1 .. Length(orbitsG)] do
77108
for i in orbitsG[orb] do
78109
orbsizes[i] := Length(orbitsG[orb]);
79110
orbpos[i] := orb;
80111
od;
81112
od;
82113

83-
innerorblist := List(orbitsG, o -> Orbits(Stabilizer(G, o[1]), moved));
84-
# FIXME: Currently unused
114+
# FIXME: In the following line, BacktrackKit uses [1..LargestMovedPoint(G)]
115+
# instead of moved (which omits non-moved points). Is this a problem?
116+
innerorblist := List(orbitsG, o -> Set(Orbits(Stabilizer(G, o[1]), moved), Set));
85117
orbitsizes := List([1 .. Length(orbitsG)],
86118
x -> List(innerorblist[x], y -> Length(orbitsG[x]) * Length(y)));
119+
biggestOrbit := Maximum(List(orbitsizes, Maximum));
87120

88121
graphlist := [];
89122
for i in [1 .. Length(orbitsG)] do
90123
orb := orbitsG[i];
91124
orbreps := [];
92-
93125
for iorb in innerorblist[i] do
94-
if not (Size(iorb) = 1 and orb[1] = iorb[1]) # No loopy orbitals
95-
then
96-
graph := List([1..maxval], x -> []);
97-
if IsEmpty(orbreps) then
98-
orbreps := fillRepElts(G, orb);
99-
fi;
100-
for val in orb do
101-
p := orbreps[val];
102-
graph[val] := List(iorb, x -> x^p);
103-
od;
104-
D := Digraph(graph);
105-
SetUnderlyingGroup(D, G);
106-
AddSet(graphlist, D);
126+
# Find reasons to not construct the orbital graph with base-pair... TODO
127+
if shouldSkipOneLargeOrbit and Size(orb) * Size(iorb) = biggestOrbit then
128+
shouldSkipOneLargeOrbit := false;
129+
continue;
130+
elif
131+
Size(orb) * Size(iorb) > cutoff # orbital graph is too big
132+
or (search and Size(iorb) = orbsizes[iorb[1]]) # orbit size unchanged
133+
or (search and orbpos[orb[1]] = orbpos[iorb[1]] and Size(iorb) + 1 = orbsizes[iorb[1]]) # orbit size only removed one point
134+
or (Length(iorb) = 1 and orb[1] = iorb[1]) # don't want to take the fixed point orbit
135+
then
136+
continue;
137+
fi;
138+
139+
# Construct the orbital graph as a Digraphs package object
140+
if IsEmpty(orbreps) then
141+
orbreps := fillRepElts(G, orb);
107142
fi;
143+
graph := List([1 .. maxval], x -> []);
144+
for val in orb do
145+
p := orbreps[val];
146+
graph[val] := List(iorb, x -> x ^ p);
147+
od;
148+
D := Digraph(graph);
149+
SetFilterObj(D, IsOrbitalGraphOfGroup);
150+
SetUnderlyingGroup(D, G);
151+
Add(graphlist, D);
108152
od;
109153
od;
110-
Perform(graphlist, function(x) SetFilterObj(x, IsOrbitalGraphOfGroup); end);
154+
# Note: `graphlist` should already be stably ordered because of the uses of `Set`
111155
return graphlist;
112156
end);
113157

tst/orbitalgraphs01.tst

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ gap> START_TEST("orbitalgraphs01.tst");
1414
gap> D8 := Group([ (1,2,3,4), (2,4) ]);; StructureDescription(D8);
1515
"D8"
1616
gap> OrbitalGraphs(D8);
17-
[ <self-paired orbital graph of D8 on 4 vertices with base-pair (1,3), 4 arcs>
17+
[ <self-paired orbital graph of D8 on 4 vertices with base-pair (1,2), 8 arcs>
1818
, <self-paired orbital graph of D8 on 4 vertices
19-
with base-pair (1,2), 8 arcs> ]
19+
with base-pair (1,3), 4 arcs> ]
2020

2121
# doc/_Chapter_Orbital_graphs.xml:101-114
2222
gap> D8 := DihedralGroup(IsPermGroup, 8);

tst/orbitals.tst

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ gap> Length(orbitals);
2727
gap> ForAll(orbitals, D -> IsDigraph(D) and DigraphNrVertices(D) = 114);
2828
true
2929
gap> List(orbitals, DigraphNrEdges);
30-
[ 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8,
31-
8, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
32-
100, 100, 200, 200, 200, 200, 2450, 2450, 2500, 2500 ]
30+
[ 2450, 100, 100, 2500, 100, 100, 200, 100, 2, 4, 100, 4, 4, 8, 100, 4, 2,
31+
100, 4, 4, 8, 2500, 100, 100, 2450, 100, 100, 200, 100, 4, 4, 100, 2, 4, 8,
32+
100, 4, 4, 100, 4, 2, 8, 200, 8, 8, 200, 8, 8, 8, 4 ]
3333
gap> Number(orbitals, IsSymmetricDigraph);
3434
8
3535
gap> Set(orbitals, x -> Minimum(DigraphEdges(x)));

0 commit comments

Comments
 (0)