30
30
InstallMethod(OrbitalGraphs, " for a permutation group and a homogeneous list" ,
31
31
[ IsPermGroup, IsHomogeneousList] ,
32
32
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,
34
35
orbpos, innerorblist, orbitsizes, orbreps, fillRepElts, maxval, moved;
35
36
36
37
if IsEmpty(points) then
@@ -48,6 +49,15 @@ function(G, points)
48
49
fi ;
49
50
moved := Intersection(points, MovedPoints(G));
50
51
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
+
51
61
fillRepElts := function (G, orb )
52
62
local val, g, reps, buildorb, gens;
53
63
reps := [] ;
@@ -65,49 +75,83 @@ function(G, points)
65
75
return reps;
66
76
end ;
67
77
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 ;
69
86
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);
74
103
75
104
# Efficently store size of orbits of values
105
+ orbsizes := [] ;
106
+ orbpos := [] ;
76
107
for orb in [ 1 .. Length(orbitsG)] do
77
108
for i in orbitsG[ orb] do
78
109
orbsizes[ i] := Length(orbitsG[ orb] );
79
110
orbpos[ i] := orb;
80
111
od ;
81
112
od ;
82
113
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));
85
117
orbitsizes := List([ 1 .. Length(orbitsG)] ,
86
118
x -> List(innerorblist[ x] , y -> Length(orbitsG[ x] ) * Length(y)));
119
+ biggestOrbit := Maximum(List(orbitsizes, Maximum));
87
120
88
121
graphlist := [] ;
89
122
for i in [ 1 .. Length(orbitsG)] do
90
123
orb := orbitsG[ i] ;
91
124
orbreps := [] ;
92
-
93
125
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);
107
142
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);
108
152
od ;
109
153
od ;
110
- Perform( graphlist, function ( x ) SetFilterObj(x, IsOrbitalGraphOfGroup); end );
154
+ # Note: ` graphlist` should already be stably ordered because of the uses of `Set`
111
155
return graphlist;
112
156
end );
113
157
0 commit comments