Path: blob/master/src/sage/groups/perm_gps/partn_ref/double_coset.pyx
8815 views
r"""1Double cosets23This module implements a general algorithm for computing double coset problems4for pairs of objects. The class of objects in question must be some kind5of structure for which an isomorphism is a permutation in $S_n$ for some $n$,6which we call here the order of the object. Given objects $X$ and $Y$,7the program returns an isomorphism in list permutation form if $X \cong Y$, and8a NULL pointer otherwise.910In order to take advantage of the algorithms in this module for a specific kind11of object, one must implement (in Cython) three functions which will be specific12to the kind of objects in question. Pointers to these functions are passed to13the main function of the module, which is \code{double_coset}. For specific14examples of implementations of these functions, see any of the files in15\code{sage.groups.perm_gps.partn_ref} beginning with "refinement." They are:1617A. \code{refine_and_return_invariant}:1819Signature:2021\code{int refine_and_return_invariant(PartitionStack *PS, void *S, int *cells_to_refine_by, int ctrb_len)}2223This function should split up cells in the partition at the top of the24partition stack in such a way that any automorphism that respects the25partition also respects the resulting partition. The array26cells_to_refine_by is a list of the beginning positions of some cells which27have been changed since the last refinement. It is not necessary to use28this in an implementation of this function, but it will affect performance.29One should consult \code{refinement_graphs} for more details and ideas for30particular implementations.3132Output:3334An integer $I$ invariant under the orbits of $S_n$. That is, if35$\gamma \in S_n$, then36$$ I(G, PS, cells_to_refine_by) = I( \gamma(G), \gamma(PS), \gamma(cells_to_refine_by) ) .$$373839B. \code{compare_structures}:4041Signature:4243\code{int compare_structures(int *gamma_1, int *gamma_2, void *S1, void *S2, int degree)}4445This function must implement a total ordering on the set of objects of fixed46order. Return:47-1 if \code{gamma_1^{-1}(S1) < gamma_2^{-1}(S2)},480 if \code{gamma_1^{-1}(S1) == gamma_2^{-1}(S2)},491 if \code{gamma_1^{-1}(S1) > gamma_2^{-1}(S2)}.5051Important note:5253The permutations are thought of as being input in inverse form, and this can54lead to subtle bugs. One is encouraged to consult existing implementations55to make sure the right thing is being done: this is so that you can avoid56*actually* needing to compute the inverse.5758C. \code{all_children_are_equivalent}:5960Signature:6162\code{bint all_children_are_equivalent(PartitionStack *PS, void *S)}6364This function must return False unless it is the case that each discrete65partition finer than the top of the partition stack is equivalent to the66others under some automorphism of S. The converse need not hold: if this is67indeed the case, it still may return False. This function is originally used68as a consequence of Lemma 2.25 in [1].6970DOCTEST:71sage: import sage.groups.perm_gps.partn_ref.double_coset7273REFERENCE:7475[1] McKay, Brendan D. Practical Graph Isomorphism. Congressus Numerantium,76Vol. 30 (1981), pp. 45-87.7778[2] Leon, Jeffrey. Permutation Group Algorithms Based on Partitions, I:79Theory and Algorithms. J. Symbolic Computation, Vol. 12 (1991), pp.80533-583.8182"""8384#*****************************************************************************85# Copyright (C) 2006 - 2011 Robert L. Miller <[email protected]>86#87# Distributed under the terms of the GNU General Public License (GPL)88# http://www.gnu.org/licenses/89#*****************************************************************************9091include 'data_structures_pyx.pxi' # includes bitsets9293cdef inline int cmp(int a, int b):94if a < b: return -195elif a == b: return 096else: return 19798# Functions99100cdef bint all_children_are_equivalent_trivial(PartitionStack *PS, void *S):101return 0102103cdef int refine_and_return_invariant_trivial(PartitionStack *PS, void *S, int *cells_to_refine_by, int ctrb_len):104return 0105106cdef int compare_perms(int *gamma_1, int *gamma_2, void *S1, void *S2, int degree):107cdef list MS1 = <list> S1108cdef list MS2 = <list> S2109cdef int i, j110for i from 0 <= i < degree:111j = cmp(MS1[gamma_1[i]], MS2[gamma_2[i]])112if j != 0: return j113return 0114115def 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]]):116"""117Given a group G generated by the given generators, tests whether the given118permutations are in the same right coset of G. Tests nontrivial input group119when using double_coset. If they are, return an element g so that120g.perm1 = perm2 (composing left to right).121122TESTS::123124sage: from sage.groups.perm_gps.partn_ref.double_coset import coset_eq125sage: coset_eq()126[5, 0, 1, 2, 3, 4]127sage: gens = [[1,2,3,0]]128sage: reps = [[0,1,2,3]]129sage: for p in SymmetricGroup(4):130... p = [p(i)-1 for i in range(1,5)]131... found = False132... for r in reps:133... if coset_eq(p, r, gens):134... found = True135... break136... if not found:137... reps.append(p)138sage: len(reps)1396140sage: gens = [[1,0,2,3],[0,1,3,2]]141sage: reps = [[0,1,2,3]]142sage: for p in SymmetricGroup(4):143... p = [p(i)-1 for i in range(1,5)]144... found = False145... for r in reps:146... if coset_eq(p, r, gens):147... found = True148... break149... if not found:150... reps.append(p)151sage: len(reps)1526153sage: gens = [[1,2,0,3]]154sage: reps = [[0,1,2,3]]155sage: for p in SymmetricGroup(4):156... p = [p(i)-1 for i in range(1,5)]157... found = False158... for r in reps:159... if coset_eq(p, r, gens):160... found = True161... break162... if not found:163... reps.append(p)164sage: len(reps)1658166167"""168cdef int i, n = len(perm1)169assert all(len(g) == n for g in gens+[perm2])170cdef PartitionStack *part = PS_new(n, 1)171cdef int *c_perm = <int *> sage_malloc(n * sizeof(int))172cdef StabilizerChain *group = SC_new(n, 1)173cdef int *isomorphism = <int *> sage_malloc(n * sizeof(int))174if part is NULL or c_perm is NULL or group is NULL or isomorphism is NULL:175sage_free(c_perm)176PS_dealloc(part)177SC_dealloc(group)178sage_free(isomorphism)179raise MemoryError180for g in gens:181for i from 0 <= i < n:182c_perm[i] = g[i]183SC_insert(group, 0, c_perm, 1)184for i from 0 <= i < n:185c_perm[i] = i186cdef bint isomorphic = double_coset(<void *> perm1, <void *> perm2, part, c_perm, n, &all_children_are_equivalent_trivial, &refine_and_return_invariant_trivial, &compare_perms, group, NULL, isomorphism)187sage_free(c_perm)188PS_dealloc(part)189SC_dealloc(group)190if isomorphic:191x = [isomorphism[i] for i from 0 <= i < n]192else:193x = False194sage_free(isomorphism)195return x196197cdef dc_work_space *allocate_dc_work_space(int n):198r"""199Allocates work space for the double_coset function. It can be200input to the function in which case it must be deallocated after the201function is called.202"""203cdef int *int_array204205cdef dc_work_space *work_space206work_space = <dc_work_space *> sage_malloc(sizeof(dc_work_space))207if work_space is NULL:208return NULL209210work_space.degree = n211int_array = <int *> sage_malloc((n*n + # for perm_stack2125*n # for int_array213)*sizeof(int))214work_space.group1 = SC_new(n)215work_space.group2 = SC_new(n)216work_space.current_ps = PS_new(n,0)217work_space.first_ps = PS_new(n,0)218work_space.bitset_array = <bitset_t *> sage_calloc((n + 2*len_of_fp_and_mcr + 1), sizeof(bitset_t))219work_space.orbits_of_subgroup = OP_new(n)220work_space.perm_stack = NULL221222if int_array is NULL or \223work_space.group1 is NULL or \224work_space.group2 is NULL or \225work_space.current_ps is NULL or \226work_space.first_ps is NULL or \227work_space.bitset_array is NULL or \228work_space.orbits_of_subgroup is NULL:229sage_free(int_array)230deallocate_dc_work_space(work_space)231return NULL232233work_space.perm_stack = int_array234work_space.int_array = int_array + n*n235236cdef int i237for i from 0 <= i < n + 2*len_of_fp_and_mcr + 1:238work_space.bitset_array[i].bits = NULL239try:240for i from 0 <= i < n + 2*len_of_fp_and_mcr + 1:241bitset_init(work_space.bitset_array[i], n)242except MemoryError:243deallocate_dc_work_space(work_space)244return NULL245return work_space246247cdef void deallocate_dc_work_space(dc_work_space *work_space):248r"""249Deallocates work space for the double_coset function.250"""251if work_space is NULL:252return253cdef int i, n = work_space.degree254if work_space.bitset_array is not NULL:255for i from 0 <= i < n + 2*len_of_fp_and_mcr + 1:256bitset_free(work_space.bitset_array[i])257sage_free(work_space.perm_stack)258SC_dealloc(work_space.group1)259SC_dealloc(work_space.group2)260PS_dealloc(work_space.current_ps)261PS_dealloc(work_space.first_ps)262sage_free(work_space.bitset_array)263OP_dealloc(work_space.orbits_of_subgroup)264sage_free(work_space)265266cdef int double_coset(void *S1, void *S2, PartitionStack *partition1, int *ordering2,267int n, bint (*all_children_are_equivalent)(PartitionStack *PS, void *S),268int (*refine_and_return_invariant)\269(PartitionStack *PS, void *S, int *cells_to_refine_by, int ctrb_len),270int (*compare_structures)(int *gamma_1, int *gamma_2, void *S1, void *S2, int degree),271StabilizerChain *input_group,272dc_work_space *work_space_prealloc, int *isom) except -1:273"""274Traverse the search space for double coset calculation.275276INPUT:277S1, S2 -- pointers to the structures278partition1 -- PartitionStack of depth 0 and degree n,279whose first partition is of the points of S1280ordering2 -- an ordering of the points of S2 representing a second partition281n -- the number of points (points are assumed to be 0,1,...,n-1)282all_children_are_equivalent -- pointer to a function283INPUT:284PS -- pointer to a partition stack285S -- pointer to the structure286OUTPUT:287bint -- returns True if it can be determined that all refinements below288the current one will result in an equivalent discrete partition289refine_and_return_invariant -- pointer to a function290INPUT:291PS -- pointer to a partition stack292S -- pointer to the structure293alpha -- an array consisting of numbers, which indicate the starting294positions of the cells to refine against (will likely be modified)295OUTPUT:296int -- returns an invariant under application of arbitrary permutations297compare_structures -- pointer to a function298INPUT:299gamma_1, gamma_2 -- (list) permutations of the points of S1 and S2300S1, S2 -- pointers to the structures301degree -- degree of gamma_1 and 2302OUTPUT:303int -- 0 if gamma_1(S1) = gamma_2(S2), otherwise -1 or 1 (see docs for cmp),304such that the set of all structures is well-ordered305input_group -- either a specified group to limit the search to,306or NULL for the full symmetric group307isom -- space to store the isomorphism to,308or NULL if isomorphism is not needed309310NOTE:311The partition ``partition1`` and the resulting partition from ``ordering2``312*must* satisfy the property that in each cell, the smallest element occurs313first!314315OUTPUT:3161 if S1 and S2 are isomorphic, otherwise 0.317318"""319cdef PartitionStack *current_ps, *first_ps, *left_ps320cdef int first_meets_current = -1321cdef int current_kids_are_same = 1322cdef int first_kids_are_same323324cdef int *indicators325326cdef OrbitPartition *orbits_of_subgroup, *orbits_of_supergroup327cdef int subgroup_primary_orbit_size = 0328cdef int minimal_in_primary_orbit329330cdef bitset_t *fixed_points_of_generators # i.e. fp331cdef bitset_t *minimal_cell_reps_of_generators # i.e. mcr332cdef int len_of_fp_and_mcr = 100333cdef int index_in_fp_and_mcr = -1334335cdef bitset_t *vertices_to_split336cdef bitset_t *vertices_have_been_reduced337cdef int *permutation, *id_perm, *cells_to_refine_by338cdef int *vertices_determining_current_stack339cdef int *perm_stack340cdef StabilizerChain *group, *old_group, *tmp_gp341342cdef int i, j, k, ell, b343cdef bint discrete, automorphism, update_label344cdef bint backtrack, new_vertex, narrow, mem_err = 0345346if n == 0:347return 0348349if work_space_prealloc is not NULL:350work_space = work_space_prealloc351else:352work_space = allocate_dc_work_space(n)353if work_space is NULL:354raise MemoryError355356# Allocate:357if input_group is not NULL:358perm_stack = work_space.perm_stack359group = work_space.group1360old_group = work_space.group2361orbits_of_supergroup = input_group.OP_scratch362SC_copy_nomalloc(group, input_group, n)363SC_identify(perm_stack, n)364365current_ps = work_space.current_ps366first_ps = work_space.first_ps367orbits_of_subgroup = work_space.orbits_of_subgroup368369indicators = work_space.int_array370permutation = work_space.int_array + n371id_perm = work_space.int_array + 2*n372cells_to_refine_by = work_space.int_array + 3*n373vertices_determining_current_stack = work_space.int_array + 4*n374375fixed_points_of_generators = work_space.bitset_array376minimal_cell_reps_of_generators = work_space.bitset_array + len_of_fp_and_mcr377vertices_to_split = work_space.bitset_array + 2*len_of_fp_and_mcr378vertices_have_been_reduced = work_space.bitset_array + 2*len_of_fp_and_mcr + n379380if work_space_prealloc is not NULL:381OP_clear(orbits_of_subgroup)382383bitset_zero(vertices_have_been_reduced[0])384left_ps = partition1385386cdef bint possible = 1387cdef bint unknown = 1388389# set up the identity permutation390for i from 0 <= i < n:391id_perm[i] = i392if ordering2 is NULL:393ordering2 = id_perm394395# Copy reordering of left_ps coming from ordering2 to current_ps.396memcpy(current_ps.entries, ordering2, n*sizeof(int))397memcpy(current_ps.levels, left_ps.levels, n*sizeof(int))398current_ps.depth = left_ps.depth399400# default values of "infinity"401for i from 0 <= i < n:402indicators[i] = -1403404# Our first refinement needs to check every cell of the partition,405# so cells_to_refine_by needs to be a list of pointers to each cell.406j = 1407cells_to_refine_by[0] = 0408for i from 0 < i < n:409if left_ps.levels[i-1] == 0:410cells_to_refine_by[j] = i411j += 1412if input_group is NULL:413k = refine_and_return_invariant(left_ps, S1, cells_to_refine_by, j)414else:415k = refine_also_by_orbits(left_ps, S1, refine_and_return_invariant,416cells_to_refine_by, j, group, perm_stack)417j = 1418cells_to_refine_by[0] = 0419for i from 0 < i < n:420if current_ps.levels[i-1] == 0:421cells_to_refine_by[j] = i422j += 1423if input_group is NULL:424j = refine_and_return_invariant(current_ps, S2, cells_to_refine_by, j)425else:426j = refine_also_by_orbits(current_ps, S2, refine_and_return_invariant,427cells_to_refine_by, j, group, perm_stack)428if k != j:429possible = 0; unknown = 0430elif not stacks_are_equivalent(left_ps, current_ps):431possible = 0; unknown = 0432else:433PS_move_all_mins_to_front(current_ps)434435# Refine down to a discrete partition436while not PS_is_discrete(left_ps):437i = left_ps.depth438k = PS_first_smallest(left_ps, vertices_to_split[i]) # writes to vertices_to_split, but this is never used439if input_group is not NULL:440OP_clear(orbits_of_supergroup)441for j from i <= j < group.base_size:442for ell from 0 <= ell < group.num_gens[j]:443OP_merge_list_perm(orbits_of_supergroup, group.generators[j] + n*ell)444b = orbits_of_supergroup.mcr[OP_find(orbits_of_supergroup, perm_stack[i*n + k])]445tmp_gp = group446group = old_group447old_group = tmp_gp448if SC_insert_base_point_nomalloc(group, old_group, i, b):449mem_err = 1450break451indicators[i] = split_point_and_refine_by_orbits(left_ps, k, S1, refine_and_return_invariant, cells_to_refine_by, group, perm_stack)452else:453indicators[i] = split_point_and_refine(left_ps, k, S1, refine_and_return_invariant, cells_to_refine_by)454bitset_unset(vertices_have_been_reduced[0], left_ps.depth)455456if not mem_err:457while not PS_is_discrete(current_ps) and possible:458i = current_ps.depth459vertices_determining_current_stack[i] = PS_first_smallest(current_ps, vertices_to_split[i])460if input_group is not NULL:461if group.parents[i][perm_stack[n*i + vertices_determining_current_stack[i]]] == -1:462possible = 0463while possible:464i = current_ps.depth465if input_group is not NULL:466j = split_point_and_refine_by_orbits(current_ps, vertices_determining_current_stack[i],467S2, refine_and_return_invariant, cells_to_refine_by, group, perm_stack)468else:469j = split_point_and_refine(current_ps,470vertices_determining_current_stack[i], S2,471refine_and_return_invariant, cells_to_refine_by)472if indicators[i] != j:473possible = 0474elif not stacks_are_equivalent(left_ps, current_ps):475possible = 0476else:477PS_move_all_mins_to_front(current_ps)478if not all_children_are_equivalent(current_ps, S2):479current_kids_are_same = current_ps.depth + 1480break481current_ps.depth -= 1482while current_ps.depth >= 0: # not possible, so look for another483i = current_ps.depth484j = vertices_determining_current_stack[i] + 1485j = bitset_next(vertices_to_split[i], j)486if j == -1:487current_ps.depth -= 1 # backtrack488else:489possible = 1490vertices_determining_current_stack[i] = j491break # found another492if possible:493if input_group is NULL:494if compare_structures(left_ps.entries, current_ps.entries, S1, S2, n) == 0:495unknown = 0496else:497PS_get_perm_from(left_ps, current_ps, permutation)498if SC_contains(group, 0, permutation, 0) and compare_structures(permutation, id_perm, S1, S2, n) == 0:499# TODO: might be slight optimization for containment using perm_stack500unknown = 0501if unknown:502first_meets_current = current_ps.depth503first_kids_are_same = current_ps.depth504PS_copy_from_to(current_ps, first_ps)505current_ps.depth -= 1506507if mem_err:508if work_space_prealloc is NULL:509deallocate_dc_work_space(work_space)510raise MemoryError511512# Main loop:513while possible and unknown and current_ps.depth != -1:514515# I. Search for a new vertex to split, and update subgroup information516new_vertex = 0517if current_ps.depth > first_meets_current:518# If we are not at a node of the first stack, reduce size of519# vertices_to_split by using the symmetries we already know.520if not bitset_check(vertices_have_been_reduced[0], current_ps.depth):521for i from 0 <= i <= index_in_fp_and_mcr:522j = 0523while j < current_ps.depth and bitset_check(fixed_points_of_generators[i], vertices_determining_current_stack[j]):524j += 1525# If each vertex split so far is fixed by generator i,526# then remove elements of vertices_to_split which are527# not minimal in their orbits under generator i.528if j == current_ps.depth:529for k from 0 <= k < n:530if bitset_check(vertices_to_split[current_ps.depth], k) and not bitset_check(minimal_cell_reps_of_generators[i], k):531bitset_flip(vertices_to_split[current_ps.depth], k)532bitset_flip(vertices_have_been_reduced[0], current_ps.depth)533# Look for a new point to split.534i = vertices_determining_current_stack[current_ps.depth] + 1535i = bitset_next(vertices_to_split[current_ps.depth], i)536if i != -1:537# There is a new point.538vertices_determining_current_stack[current_ps.depth] = i539new_vertex = 1540else:541# No new point: backtrack.542current_ps.depth -= 1543else:544# If we are at a node of the first stack, the above reduction545# will not help. Also, we must update information about546# primary orbits here.547if current_ps.depth < first_meets_current:548# If we are done searching under this part of the first549# stack, then first_meets_current is one higher, and we550# are looking at a new primary orbit (corresponding to a551# larger subgroup in the stabilizer chain).552first_meets_current = current_ps.depth553for i from 0 <= i < n:554if bitset_check(vertices_to_split[current_ps.depth], i):555minimal_in_primary_orbit = i556break557while 1:558i = vertices_determining_current_stack[current_ps.depth]559# This was the last point to be split here.560# If it is in the same orbit as minimal_in_primary_orbit,561# then count it as an element of the primary orbit.562if OP_find(orbits_of_subgroup, i) == OP_find(orbits_of_subgroup, minimal_in_primary_orbit):563subgroup_primary_orbit_size += 1564# Look for a new point to split.565i += 1566i = bitset_next(vertices_to_split[current_ps.depth], i)567if i != -1:568# There is a new point.569vertices_determining_current_stack[current_ps.depth] = i570if orbits_of_subgroup.mcr[OP_find(orbits_of_subgroup, i)] == i:571new_vertex = 1572break573else:574# No new point: backtrack.575# Note that now, we are backtracking up the first stack.576vertices_determining_current_stack[current_ps.depth] = -1577# If every choice of point to split gave something in the578# (same!) primary orbit, then all children of the first579# stack at this point are equivalent.580j = 0581for i from 0 <= i < n:582if bitset_check(vertices_to_split[current_ps.depth], i):583j += 1584if j == subgroup_primary_orbit_size and first_kids_are_same == current_ps.depth+1:585first_kids_are_same = current_ps.depth586# Backtrack.587subgroup_primary_orbit_size = 0588current_ps.depth -= 1589break590if not new_vertex:591continue592593if current_kids_are_same > current_ps.depth + 1:594current_kids_are_same = current_ps.depth + 1595596# II. Refine down to a discrete partition, or until597# we leave the part of the tree we are interested in598discrete = 0599while 1:600i = current_ps.depth601while 1:602if input_group is not NULL:603k = split_point_and_refine_by_orbits(current_ps,604vertices_determining_current_stack[i], S2,605refine_and_return_invariant, cells_to_refine_by,606group, perm_stack)607update_perm_stack(group, current_ps.depth, vertices_determining_current_stack[i], perm_stack)608else:609k = split_point_and_refine(current_ps,610vertices_determining_current_stack[i], S2,611refine_and_return_invariant, cells_to_refine_by)612PS_move_all_mins_to_front(current_ps)613if indicators[i] != k:614possible = 0615elif not stacks_are_equivalent(left_ps, current_ps):616possible = 0617if PS_is_discrete(current_ps):618break619vertices_determining_current_stack[current_ps.depth] = PS_first_smallest(current_ps, vertices_to_split[current_ps.depth])620if input_group is not NULL:621if group.parents[current_ps.depth][perm_stack[n*current_ps.depth + vertices_determining_current_stack[current_ps.depth]]] == -1:622possible = 0623if not possible:624j = vertices_determining_current_stack[i] + 1625j = bitset_next(vertices_to_split[i], j)626if j == -1:627break628else:629possible = 1630vertices_determining_current_stack[i] = j631current_ps.depth -= 1 # reset for next refinement632else: break633if not possible:634break635if PS_is_discrete(current_ps):636break637bitset_unset(vertices_have_been_reduced[0], current_ps.depth)638if not all_children_are_equivalent(current_ps, S2):639current_kids_are_same = current_ps.depth + 1640641# III. Check for automorphisms and isomorphisms642automorphism = 0643if possible:644PS_get_perm_from(first_ps, current_ps, permutation)645if compare_structures(permutation, id_perm, S2, S2, n) == 0:646if input_group is NULL or SC_contains(group, 0, permutation, 0):647# TODO: might be slight optimization for containment using perm_stack648automorphism = 1649if not automorphism and possible:650# if we get here, discrete must be true651if current_ps.depth != left_ps.depth:652possible = 0653elif input_group is NULL:654if compare_structures(left_ps.entries, current_ps.entries, S1, S2, n) == 0:655unknown = 0656break657else:658possible = 0659else:660PS_get_perm_from(left_ps, current_ps, permutation)661if SC_contains(group, 0, permutation, 0) and compare_structures(permutation, id_perm, S1, S2, n) == 0:662# TODO: might be slight optimization for containment using perm_stack663unknown = 0664break665else:666possible = 0667if automorphism:668if index_in_fp_and_mcr < len_of_fp_and_mcr - 1:669index_in_fp_and_mcr += 1670bitset_zero(fixed_points_of_generators[index_in_fp_and_mcr])671bitset_zero(minimal_cell_reps_of_generators[index_in_fp_and_mcr])672for i from 0 <= i < n:673if permutation[i] == i:674bitset_set(fixed_points_of_generators[index_in_fp_and_mcr], i)675bitset_set(minimal_cell_reps_of_generators[index_in_fp_and_mcr], i)676else:677bitset_unset(fixed_points_of_generators[index_in_fp_and_mcr], i)678k = i679j = permutation[i]680while j != i:681if j < k: k = j682j = permutation[j]683if k == i:684bitset_set(minimal_cell_reps_of_generators[index_in_fp_and_mcr], i)685else:686bitset_unset(minimal_cell_reps_of_generators[index_in_fp_and_mcr], i)687current_ps.depth = first_meets_current688if OP_merge_list_perm(orbits_of_subgroup, permutation): # if permutation made orbits coarser689if orbits_of_subgroup.mcr[OP_find(orbits_of_subgroup, minimal_in_primary_orbit)] != minimal_in_primary_orbit:690continue # main loop691if bitset_check(vertices_have_been_reduced[0], current_ps.depth):692bitset_and(vertices_to_split[current_ps.depth], vertices_to_split[current_ps.depth], minimal_cell_reps_of_generators[index_in_fp_and_mcr])693continue # main loop694if not possible:695possible = 1696i = current_ps.depth697current_ps.depth = current_kids_are_same-1698if i == current_kids_are_same:699continue # main loop700if index_in_fp_and_mcr < len_of_fp_and_mcr - 1:701index_in_fp_and_mcr += 1702bitset_zero(fixed_points_of_generators[index_in_fp_and_mcr])703bitset_zero(minimal_cell_reps_of_generators[index_in_fp_and_mcr])704j = current_ps.depth705current_ps.depth = i # just for mcr and fixed functions...706for i from 0 <= i < n:707if PS_is_mcr(current_ps, i):708bitset_set(minimal_cell_reps_of_generators[index_in_fp_and_mcr], i)709if PS_is_fixed(current_ps, i):710bitset_set(fixed_points_of_generators[index_in_fp_and_mcr], i)711current_ps.depth = j712if bitset_check(vertices_have_been_reduced[0], current_ps.depth):713bitset_and(vertices_to_split[current_ps.depth], vertices_to_split[current_ps.depth], minimal_cell_reps_of_generators[index_in_fp_and_mcr])714715# End of main loop.716if possible and not unknown and isom is not NULL:717for i from 0 <= i < n:718isom[left_ps.entries[i]] = current_ps.entries[i]719720# Deallocate:721if work_space_prealloc is NULL:722deallocate_dc_work_space(work_space)723return 1 if (possible and not unknown) else 0724725726727728729730731