Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/groups/perm_gps/partn_ref/double_coset.pyx
4097 views
1
r"""
2
Double cosets
3
4
This module implements a general algorithm for computing double coset problems
5
for pairs of objects. The class of objects in question must be some kind
6
of structure for which an isomorphism is a permutation in $S_n$ for some $n$,
7
which we call here the order of the object. Given objects $X$ and $Y$,
8
the program returns an isomorphism in list permutation form if $X \cong Y$, and
9
a NULL pointer otherwise.
10
11
In order to take advantage of the algorithms in this module for a specific kind
12
of object, one must implement (in Cython) three functions which will be specific
13
to the kind of objects in question. Pointers to these functions are passed to
14
the main function of the module, which is \code{double_coset}. For specific
15
examples of implementations of these functions, see any of the files in
16
\code{sage.groups.perm_gps.partn_ref} beginning with "refinement." They are:
17
18
A. \code{refine_and_return_invariant}:
19
20
Signature:
21
22
\code{int refine_and_return_invariant(PartitionStack *PS, void *S, int *cells_to_refine_by, int ctrb_len)}
23
24
This function should split up cells in the partition at the top of the
25
partition stack in such a way that any automorphism that respects the
26
partition also respects the resulting partition. The array
27
cells_to_refine_by is a list of the beginning positions of some cells which
28
have been changed since the last refinement. It is not necessary to use
29
this in an implementation of this function, but it will affect performance.
30
One should consult \code{refinement_graphs} for more details and ideas for
31
particular implementations.
32
33
Output:
34
35
An integer $I$ invariant under the orbits of $S_n$. That is, if
36
$\gamma \in S_n$, then
37
$$ I(G, PS, cells_to_refine_by) = I( \gamma(G), \gamma(PS), \gamma(cells_to_refine_by) ) .$$
38
39
40
B. \code{compare_structures}:
41
42
Signature:
43
44
\code{int compare_structures(int *gamma_1, int *gamma_2, void *S1, void *S2)}
45
46
This function must implement a total ordering on the set of objects of fixed
47
order. Return:
48
-1 if \code{gamma_1^{-1}(S1) < gamma_2^{-1}(S2)},
49
0 if \code{gamma_1^{-1}(S1) == gamma_2^{-1}(S2)},
50
1 if \code{gamma_1^{-1}(S1) > gamma_2^{-1}(S2)}.
51
52
Important note:
53
54
The permutations are thought of as being input in inverse form, and this can
55
lead to subtle bugs. One is encouraged to consult existing implementations
56
to make sure the right thing is being done: this is so that you can avoid
57
*actually* needing to compute the inverse.
58
59
C. \code{all_children_are_equivalent}:
60
61
Signature:
62
63
\code{bint all_children_are_equivalent(PartitionStack *PS, void *S)}
64
65
This function must return False unless it is the case that each discrete
66
partition finer than the top of the partition stack is equivalent to the
67
others under some automorphism of S. The converse need not hold: if this is
68
indeed the case, it still may return False. This function is originally used
69
as a consequence of Lemma 2.25 in [1].
70
71
DOCTEST:
72
sage: import sage.groups.perm_gps.partn_ref.double_coset
73
74
REFERENCE:
75
76
[1] McKay, Brendan D. Practical Graph Isomorphism. Congressus Numerantium,
77
Vol. 30 (1981), pp. 45-87.
78
79
[2] Leon, Jeffrey. Permutation Group Algorithms Based on Partitions, I:
80
Theory and Algorithms. J. Symbolic Computation, Vol. 12 (1991), pp.
81
533-583.
82
83
"""
84
85
#*****************************************************************************
86
# Copyright (C) 2006 - 2011 Robert L. Miller <[email protected]>
87
#
88
# Distributed under the terms of the GNU General Public License (GPL)
89
# http://www.gnu.org/licenses/
90
#*****************************************************************************
91
92
include 'data_structures_pyx.pxi' # includes bitsets
93
94
cdef inline int cmp(int a, int b):
95
if a < b: return -1
96
elif a == b: return 0
97
else: return 1
98
99
# Functions
100
101
cdef bint all_children_are_equivalent_trivial(PartitionStack *PS, void *S):
102
return 0
103
104
cdef int refine_and_return_invariant_trivial(PartitionStack *PS, void *S, int *cells_to_refine_by, int ctrb_len):
105
return 0
106
107
cdef int compare_perms(int *gamma_1, int *gamma_2, void *S1, void *S2):
108
cdef list MS1 = <list> S1
109
cdef list MS2 = <list> S2
110
cdef int i, j
111
for i from 0 <= i < len(MS1):
112
j = cmp(MS1[gamma_1[i]], MS2[gamma_2[i]])
113
if j != 0: return j
114
return 0
115
116
def coset_eq(list perm1=[0,1,2,3,4,5], list perm2=[1,2,3,4,5,0], list gens=[[1,2,3,4,5,0]]):
117
"""
118
Given a group G generated by the given generators, tests whether the given
119
permutations are in the same right coset of G. Tests nontrivial input group
120
when using double_coset. If they are, return an element g so that
121
g.perm1 = perm2 (composing left to right).
122
123
TESTS::
124
125
sage: from sage.groups.perm_gps.partn_ref.double_coset import coset_eq
126
sage: coset_eq()
127
[5, 0, 1, 2, 3, 4]
128
sage: gens = [[1,2,3,0]]
129
sage: reps = [[0,1,2,3]]
130
sage: for p in SymmetricGroup(4):
131
... p = [a-1 for a in p.list()]
132
... found = False
133
... for r in reps:
134
... if coset_eq(p, r, gens):
135
... found = True
136
... break
137
... if not found:
138
... reps.append(p)
139
sage: len(reps)
140
6
141
sage: gens = [[1,0,2,3],[0,1,3,2]]
142
sage: reps = [[0,1,2,3]]
143
sage: for p in SymmetricGroup(4):
144
... p = [a-1 for a in p.list()]
145
... found = False
146
... for r in reps:
147
... if coset_eq(p, r, gens):
148
... found = True
149
... break
150
... if not found:
151
... reps.append(p)
152
sage: len(reps)
153
6
154
sage: gens = [[1,2,0,3]]
155
sage: reps = [[0,1,2,3]]
156
sage: for p in SymmetricGroup(4):
157
... p = [a-1 for a in p.list()]
158
... found = False
159
... for r in reps:
160
... if coset_eq(p, r, gens):
161
... found = True
162
... break
163
... if not found:
164
... reps.append(p)
165
sage: len(reps)
166
8
167
168
"""
169
cdef int i, n = len(perm1)
170
assert all(len(g) == n for g in gens+[perm2])
171
cdef PartitionStack *part = PS_new(n, 1)
172
cdef int *c_perm = <int *> sage_malloc(n * sizeof(int))
173
cdef StabilizerChain *group = SC_new(n, 1)
174
if part is NULL or c_perm is NULL or group is NULL:
175
sage_free(c_perm)
176
PS_dealloc(part)
177
SC_dealloc(group)
178
raise MemoryError
179
for g in gens:
180
for i from 0 <= i < n:
181
c_perm[i] = g[i]
182
SC_insert(group, 0, c_perm, 1)
183
for i from 0 <= i < n:
184
c_perm[i] = i
185
cdef int *output = double_coset(<void *> perm1, <void *> perm2, part, c_perm, n, &all_children_are_equivalent_trivial, &refine_and_return_invariant_trivial, &compare_perms, group)
186
sage_free(c_perm)
187
PS_dealloc(part)
188
SC_dealloc(group)
189
if output is NULL:
190
return False
191
else:
192
x = [output[i] for i from 0 <= i < n]
193
sage_free(output)
194
return x
195
196
cdef int *double_coset(void *S1, void *S2, PartitionStack *partition1, int *ordering2,
197
int n, bint (*all_children_are_equivalent)(PartitionStack *PS, void *S),
198
int (*refine_and_return_invariant)\
199
(PartitionStack *PS, void *S, int *cells_to_refine_by, int ctrb_len),
200
int (*compare_structures)(int *gamma_1, int *gamma_2, void *S1, void *S2),
201
StabilizerChain *input_group):
202
"""
203
Traverse the search space for double coset calculation.
204
205
INPUT:
206
S1, S2 -- pointers to the structures
207
partition1 -- PartitionStack of depth 0 and degree n,
208
whose first partition is of the points of S1
209
ordering2 -- an ordering of the points of S2 representing a second partition
210
n -- the number of points (points are assumed to be 0,1,...,n-1)
211
all_children_are_equivalent -- pointer to a function
212
INPUT:
213
PS -- pointer to a partition stack
214
S -- pointer to the structure
215
OUTPUT:
216
bint -- returns True if it can be determined that all refinements below
217
the current one will result in an equivalent discrete partition
218
refine_and_return_invariant -- pointer to a function
219
INPUT:
220
PS -- pointer to a partition stack
221
S -- pointer to the structure
222
alpha -- an array consisting of numbers, which indicate the starting
223
positions of the cells to refine against (will likely be modified)
224
OUTPUT:
225
int -- returns an invariant under application of arbitrary permutations
226
compare_structures -- pointer to a function
227
INPUT:
228
gamma_1, gamma_2 -- (list) permutations of the points of S1 and S2
229
S1, S2 -- pointers to the structures
230
OUTPUT:
231
int -- 0 if gamma_1(S1) = gamma_2(S2), otherwise -1 or 1 (see docs for cmp),
232
such that the set of all structures is well-ordered
233
234
NOTE:
235
The partition ``partition1`` and the resulting partition from ``ordering2``
236
*must* satisfy the property that in each cell, the smallest element occurs
237
first!
238
239
OUTPUT:
240
If S1 and S2 are isomorphic, a pointer to an integer array representing an
241
isomorphism. Otherwise, a NULL pointer.
242
243
"""
244
cdef PartitionStack *current_ps, *first_ps, *left_ps
245
cdef int first_meets_current = -1
246
cdef int current_kids_are_same = 1
247
cdef int first_kids_are_same
248
249
cdef int *indicators
250
251
cdef OrbitPartition *orbits_of_subgroup
252
cdef int subgroup_primary_orbit_size = 0
253
cdef int minimal_in_primary_orbit
254
255
cdef bitset_t *fixed_points_of_generators # i.e. fp
256
cdef bitset_t *minimal_cell_reps_of_generators # i.e. mcr
257
cdef int len_of_fp_and_mcr = 100
258
cdef int index_in_fp_and_mcr = -1
259
260
cdef bitset_t *vertices_to_split
261
cdef bitset_t vertices_have_been_reduced
262
cdef int *permutation, *id_perm, *cells_to_refine_by
263
cdef int *vertices_determining_current_stack
264
cdef int *perm_stack
265
cdef StabilizerChain *group, *old_group, *tmp_gp
266
267
cdef int *output
268
269
cdef int i, j, k
270
cdef bint discrete, automorphism, update_label
271
cdef bint backtrack, new_vertex, narrow, mem_err = 0
272
273
if n == 0:
274
return NULL
275
276
cdef int *int_array = <int *> sage_malloc( 5*n * sizeof(int) )
277
output = <int *> sage_malloc( n * sizeof(int) )
278
if input_group is not NULL:
279
perm_stack = <int *> sage_malloc( n*n * sizeof(int) )
280
group = SC_copy(input_group, n)
281
old_group = SC_new(n)
282
if perm_stack is NULL or group is NULL or old_group is NULL:
283
mem_err = 1
284
else:
285
SC_identify(perm_stack, n)
286
cdef bitset_t *bitset_array = <bitset_t *> sage_malloc( (n+2*len_of_fp_and_mcr) * sizeof(bitset_t) )
287
left_ps = partition1
288
current_ps = PS_new(n, 0)
289
orbits_of_subgroup = OP_new(n)
290
291
if int_array is NULL or output is NULL or bitset_array is NULL or \
292
current_ps is NULL or orbits_of_subgroup is NULL:
293
mem_err = 1
294
295
if not mem_err:
296
indicators = int_array
297
permutation = int_array + n
298
id_perm = int_array + 2*n
299
cells_to_refine_by = int_array + 3*n
300
vertices_determining_current_stack = int_array + 4*n
301
302
fixed_points_of_generators = bitset_array
303
minimal_cell_reps_of_generators = bitset_array + len_of_fp_and_mcr
304
vertices_to_split = bitset_array + 2*len_of_fp_and_mcr
305
try:
306
for i from 0 <= i < n+2*len_of_fp_and_mcr:
307
bitset_init(bitset_array[i], n)
308
bitset_init(vertices_have_been_reduced, n)
309
except MemoryError:
310
mem_err = 1
311
312
cdef bint possible = 1
313
cdef bint unknown = 1
314
315
if not mem_err:
316
bitset_zero(vertices_have_been_reduced)
317
318
# set up the identity permutation
319
for i from 0 <= i < n:
320
id_perm[i] = i
321
if ordering2 is NULL:
322
ordering2 = id_perm
323
324
# Copy reordering of left_ps coming from ordering2 to current_ps.
325
for i from 0 <= i < n:
326
current_ps.entries[i] = ordering2[i] # memcpy faster?
327
current_ps.levels[i] = left_ps.levels[i]
328
# note that current_ps depth and degree already set
329
330
# default values of "infinity"
331
for i from 0 <= i < n:
332
indicators[i] = -1
333
334
# Our first refinement needs to check every cell of the partition,
335
# so cells_to_refine_by needs to be a list of pointers to each cell.
336
j = 1
337
cells_to_refine_by[0] = 0
338
for i from 0 < i < n:
339
if left_ps.levels[i-1] == 0:
340
cells_to_refine_by[j] = i
341
j += 1
342
if input_group is NULL:
343
k = refine_and_return_invariant(left_ps, S1, cells_to_refine_by, j)
344
else:
345
k = refine_also_by_orbits(left_ps, S1, refine_and_return_invariant,
346
cells_to_refine_by, j, group, perm_stack)
347
348
j = 1
349
cells_to_refine_by[0] = 0
350
for i from 0 < i < n:
351
if current_ps.levels[i-1] == 0:
352
cells_to_refine_by[j] = i
353
j += 1
354
if input_group is NULL:
355
j = refine_and_return_invariant(current_ps, S2, cells_to_refine_by, j)
356
else:
357
j = refine_also_by_orbits(current_ps, S2, refine_and_return_invariant,
358
cells_to_refine_by, j, group, perm_stack)
359
360
if k != j:
361
possible = 0; unknown = 0
362
elif not stacks_are_equivalent(left_ps, current_ps):
363
possible = 0; unknown = 0
364
else:
365
PS_move_all_mins_to_front(current_ps)
366
367
first_ps = NULL
368
# Refine down to a discrete partition
369
while not PS_is_discrete(left_ps):
370
i = left_ps.depth
371
k = PS_first_smallest(left_ps, vertices_to_split[i]) # writes to vertices_to_split, but this is never used
372
if input_group is not NULL:
373
# split the point
374
left_ps.depth += 1
375
PS_clear(left_ps)
376
cells_to_refine_by[0] = PS_split_point(left_ps, k)
377
# update the base
378
tmp_gp = group
379
group = old_group
380
old_group = tmp_gp
381
if SC_insert_base_point_nomalloc(group, old_group, i, k):
382
mem_err = 1
383
break
384
SC_identify(perm_stack + n*left_ps.depth, n)
385
# do the refinements
386
indicators[i] = refine_also_by_orbits(left_ps, S1, refine_and_return_invariant, cells_to_refine_by, 1, group, perm_stack)
387
else:
388
indicators[i] = split_point_and_refine(left_ps, k, S1, refine_and_return_invariant, cells_to_refine_by)
389
bitset_unset(vertices_have_been_reduced, left_ps.depth)
390
if not mem_err:
391
while not PS_is_discrete(current_ps) and possible:
392
i = current_ps.depth
393
vertices_determining_current_stack[i] = PS_first_smallest(current_ps, vertices_to_split[i])
394
if input_group is not NULL:
395
if group.parents[i][perm_stack[n*i + vertices_determining_current_stack[i]]] == -1:
396
possible = 0
397
while possible:
398
i = current_ps.depth
399
if input_group is not NULL:
400
# split the point
401
current_ps.depth += 1
402
PS_clear(current_ps)
403
cells_to_refine_by[0] = PS_split_point(current_ps, vertices_determining_current_stack[i])
404
# update the base
405
tmp_gp = group
406
group = old_group
407
old_group = tmp_gp
408
if SC_insert_base_point_nomalloc(group, old_group, i, vertices_determining_current_stack[i]):
409
mem_err = 1
410
break
411
# update perm_stack
412
update_perm_stack(group, current_ps.depth, vertices_determining_current_stack[i], perm_stack)
413
# do the refinements
414
j = refine_also_by_orbits(current_ps, S2, refine_and_return_invariant, cells_to_refine_by, 1, group, perm_stack)
415
else:
416
j = split_point_and_refine(current_ps,
417
vertices_determining_current_stack[i], S2,
418
refine_and_return_invariant, cells_to_refine_by)
419
if indicators[i] != j:
420
possible = 0
421
elif not stacks_are_equivalent(left_ps, current_ps):
422
possible = 0
423
else:
424
PS_move_all_mins_to_front(current_ps)
425
if not all_children_are_equivalent(current_ps, S2):
426
current_kids_are_same = current_ps.depth + 1
427
break
428
current_ps.depth -= 1
429
while current_ps.depth >= 0: # not possible, so look for another
430
i = current_ps.depth
431
j = vertices_determining_current_stack[i] + 1
432
j = bitset_next(vertices_to_split[i], j)
433
if j == -1:
434
current_ps.depth -= 1 # backtrack
435
else:
436
possible = 1
437
vertices_determining_current_stack[i] = j
438
break # found another
439
if possible:
440
if input_group is NULL:
441
if compare_structures(left_ps.entries, current_ps.entries, S1, S2) == 0:
442
unknown = 0
443
else:
444
PS_get_perm_from(left_ps, current_ps, permutation)
445
if SC_contains(group, 0, permutation, 0) and compare_structures(permutation, id_perm, S1, S2) == 0:
446
# TODO: might be slight optimization for containment using perm_stack
447
unknown = 0
448
if unknown:
449
first_meets_current = current_ps.depth
450
first_kids_are_same = current_ps.depth
451
first_ps = PS_copy(current_ps)
452
if first_ps is NULL:
453
mem_err = 1
454
current_ps.depth -= 1
455
456
if mem_err:
457
sage_free(int_array)
458
if input_group is not NULL:
459
sage_free(perm_stack)
460
SC_dealloc(group)
461
SC_dealloc(old_group)
462
OP_dealloc(orbits_of_subgroup)
463
sage_free(output)
464
if bitset_array is not NULL:
465
for i from 0 <= i < n+2*len_of_fp_and_mcr:
466
bitset_free(bitset_array[i])
467
bitset_free(vertices_have_been_reduced)
468
sage_free(bitset_array)
469
PS_dealloc(current_ps)
470
raise MemoryError
471
472
# Main loop:
473
while possible and unknown and current_ps.depth != -1:
474
475
# I. Search for a new vertex to split, and update subgroup information
476
new_vertex = 0
477
if current_ps.depth > first_meets_current:
478
# If we are not at a node of the first stack, reduce size of
479
# vertices_to_split by using the symmetries we already know.
480
if not bitset_check(vertices_have_been_reduced, current_ps.depth):
481
for i from 0 <= i <= index_in_fp_and_mcr:
482
j = 0
483
while j < current_ps.depth and bitset_check(fixed_points_of_generators[i], vertices_determining_current_stack[j]):
484
j += 1
485
# If each vertex split so far is fixed by generator i,
486
# then remove elements of vertices_to_split which are
487
# not minimal in their orbits under generator i.
488
if j == current_ps.depth:
489
for k from 0 <= k < n:
490
if bitset_check(vertices_to_split[current_ps.depth], k) and not bitset_check(minimal_cell_reps_of_generators[i], k):
491
bitset_flip(vertices_to_split[current_ps.depth], k)
492
bitset_flip(vertices_have_been_reduced, current_ps.depth)
493
# Look for a new point to split.
494
i = vertices_determining_current_stack[current_ps.depth] + 1
495
i = bitset_next(vertices_to_split[current_ps.depth], i)
496
if i != -1:
497
# There is a new point.
498
vertices_determining_current_stack[current_ps.depth] = i
499
new_vertex = 1
500
else:
501
# No new point: backtrack.
502
current_ps.depth -= 1
503
else:
504
# If we are at a node of the first stack, the above reduction
505
# will not help. Also, we must update information about
506
# primary orbits here.
507
if current_ps.depth < first_meets_current:
508
# If we are done searching under this part of the first
509
# stack, then first_meets_current is one higher, and we
510
# are looking at a new primary orbit (corresponding to a
511
# larger subgroup in the stabilizer chain).
512
first_meets_current = current_ps.depth
513
for i from 0 <= i < n:
514
if bitset_check(vertices_to_split[current_ps.depth], i):
515
minimal_in_primary_orbit = i
516
break
517
while 1:
518
i = vertices_determining_current_stack[current_ps.depth]
519
# This was the last point to be split here.
520
# If it is in the same orbit as minimal_in_primary_orbit,
521
# then count it as an element of the primary orbit.
522
if OP_find(orbits_of_subgroup, i) == OP_find(orbits_of_subgroup, minimal_in_primary_orbit):
523
subgroup_primary_orbit_size += 1
524
# Look for a new point to split.
525
i += 1
526
i = bitset_next(vertices_to_split[current_ps.depth], i)
527
if i != -1:
528
# There is a new point.
529
vertices_determining_current_stack[current_ps.depth] = i
530
if orbits_of_subgroup.mcr[OP_find(orbits_of_subgroup, i)] == i:
531
new_vertex = 1
532
break
533
else:
534
# No new point: backtrack.
535
# Note that now, we are backtracking up the first stack.
536
vertices_determining_current_stack[current_ps.depth] = -1
537
# If every choice of point to split gave something in the
538
# (same!) primary orbit, then all children of the first
539
# stack at this point are equivalent.
540
j = 0
541
for i from 0 <= i < n:
542
if bitset_check(vertices_to_split[current_ps.depth], i):
543
j += 1
544
if j == subgroup_primary_orbit_size and first_kids_are_same == current_ps.depth+1:
545
first_kids_are_same = current_ps.depth
546
# Backtrack.
547
subgroup_primary_orbit_size = 0
548
current_ps.depth -= 1
549
break
550
if not new_vertex:
551
continue
552
553
if current_kids_are_same > current_ps.depth + 1:
554
current_kids_are_same = current_ps.depth + 1
555
556
# II. Refine down to a discrete partition, or until
557
# we leave the part of the tree we are interested in
558
discrete = 0
559
while 1:
560
i = current_ps.depth
561
while 1:
562
if input_group is not NULL:
563
k = split_point_and_refine_by_orbits(current_ps,
564
vertices_determining_current_stack[i], S2,
565
refine_and_return_invariant, cells_to_refine_by,
566
group, perm_stack)
567
update_perm_stack(group, current_ps.depth, vertices_determining_current_stack[i], perm_stack)
568
else:
569
k = split_point_and_refine(current_ps,
570
vertices_determining_current_stack[i], S2,
571
refine_and_return_invariant, cells_to_refine_by)
572
PS_move_all_mins_to_front(current_ps)
573
if indicators[i] != k:
574
possible = 0
575
elif not stacks_are_equivalent(left_ps, current_ps):
576
possible = 0
577
if PS_is_discrete(current_ps):
578
break
579
vertices_determining_current_stack[current_ps.depth] = PS_first_smallest(current_ps, vertices_to_split[current_ps.depth])
580
if input_group is not NULL:
581
if group.parents[current_ps.depth][perm_stack[n*current_ps.depth + vertices_determining_current_stack[current_ps.depth]]] == -1:
582
possible = 0
583
if not possible:
584
j = vertices_determining_current_stack[i] + 1
585
j = bitset_next(vertices_to_split[i], j)
586
if j == -1:
587
break
588
else:
589
possible = 1
590
vertices_determining_current_stack[i] = j
591
current_ps.depth -= 1 # reset for next refinement
592
else: break
593
if not possible:
594
break
595
if PS_is_discrete(current_ps):
596
break
597
bitset_unset(vertices_have_been_reduced, current_ps.depth)
598
if not all_children_are_equivalent(current_ps, S2):
599
current_kids_are_same = current_ps.depth + 1
600
601
# III. Check for automorphisms and isomorphisms
602
automorphism = 0
603
if possible:
604
PS_get_perm_from(first_ps, current_ps, permutation)
605
if compare_structures(permutation, id_perm, S2, S2) == 0:
606
if input_group is NULL or SC_contains(group, 0, permutation, 0):
607
# TODO: might be slight optimization for containment using perm_stack
608
automorphism = 1
609
if not automorphism and possible:
610
# if we get here, discrete must be true
611
if current_ps.depth != left_ps.depth:
612
possible = 0
613
elif input_group is NULL:
614
if compare_structures(left_ps.entries, current_ps.entries, S1, S2) == 0:
615
unknown = 0
616
break
617
else:
618
possible = 0
619
else:
620
PS_get_perm_from(left_ps, current_ps, permutation)
621
if SC_contains(group, 0, permutation, 0) and compare_structures(permutation, id_perm, S1, S2) == 0:
622
# TODO: might be slight optimization for containment using perm_stack
623
unknown = 0
624
break
625
else:
626
possible = 0
627
if automorphism:
628
if index_in_fp_and_mcr < len_of_fp_and_mcr - 1:
629
index_in_fp_and_mcr += 1
630
bitset_zero(fixed_points_of_generators[index_in_fp_and_mcr])
631
bitset_zero(minimal_cell_reps_of_generators[index_in_fp_and_mcr])
632
for i from 0 <= i < n:
633
if permutation[i] == i:
634
bitset_set(fixed_points_of_generators[index_in_fp_and_mcr], i)
635
bitset_set(minimal_cell_reps_of_generators[index_in_fp_and_mcr], i)
636
else:
637
bitset_unset(fixed_points_of_generators[index_in_fp_and_mcr], i)
638
k = i
639
j = permutation[i]
640
while j != i:
641
if j < k: k = j
642
j = permutation[j]
643
if k == i:
644
bitset_set(minimal_cell_reps_of_generators[index_in_fp_and_mcr], i)
645
else:
646
bitset_unset(minimal_cell_reps_of_generators[index_in_fp_and_mcr], i)
647
current_ps.depth = first_meets_current
648
if OP_merge_list_perm(orbits_of_subgroup, permutation): # if permutation made orbits coarser
649
if orbits_of_subgroup.mcr[OP_find(orbits_of_subgroup, minimal_in_primary_orbit)] != minimal_in_primary_orbit:
650
continue # main loop
651
if bitset_check(vertices_have_been_reduced, current_ps.depth):
652
bitset_and(vertices_to_split[current_ps.depth], vertices_to_split[current_ps.depth], minimal_cell_reps_of_generators[index_in_fp_and_mcr])
653
continue # main loop
654
if not possible:
655
possible = 1
656
i = current_ps.depth
657
current_ps.depth = current_kids_are_same-1
658
if i == current_kids_are_same:
659
continue # main loop
660
if index_in_fp_and_mcr < len_of_fp_and_mcr - 1:
661
index_in_fp_and_mcr += 1
662
bitset_zero(fixed_points_of_generators[index_in_fp_and_mcr])
663
bitset_zero(minimal_cell_reps_of_generators[index_in_fp_and_mcr])
664
j = current_ps.depth
665
current_ps.depth = i # just for mcr and fixed functions...
666
for i from 0 <= i < n:
667
if PS_is_mcr(current_ps, i):
668
bitset_set(minimal_cell_reps_of_generators[index_in_fp_and_mcr], i)
669
if PS_is_fixed(current_ps, i):
670
bitset_set(fixed_points_of_generators[index_in_fp_and_mcr], i)
671
current_ps.depth = j
672
if bitset_check(vertices_have_been_reduced, current_ps.depth):
673
bitset_and(vertices_to_split[current_ps.depth], vertices_to_split[current_ps.depth], minimal_cell_reps_of_generators[index_in_fp_and_mcr])
674
675
# End of main loop.
676
677
if possible and not unknown:
678
for i from 0 <= i < n:
679
output[left_ps.entries[i]] = current_ps.entries[i]
680
else:
681
sage_free(output)
682
output = NULL
683
684
# Deallocate:
685
sage_free(int_array)
686
OP_dealloc(orbits_of_subgroup)
687
if bitset_array is not NULL:
688
for i from 0 <= i < n+2*len_of_fp_and_mcr:
689
bitset_free(bitset_array[i])
690
bitset_free(vertices_have_been_reduced)
691
sage_free(bitset_array)
692
if input_group is not NULL:
693
sage_free(perm_stack)
694
SC_dealloc(group)
695
SC_dealloc(old_group)
696
PS_dealloc(first_ps)
697
PS_dealloc(current_ps)
698
return output
699
700
701
702
703
704
705