Path: blob/master/src/sage/groups/perm_gps/partn_ref/refinement_sets.pyx
8817 views
r"""1Partition backtrack functions for sets23DOCTEST:4sage: import sage.groups.perm_gps.partn_ref.refinement_sets56REFERENCE:78[1] McKay, Brendan D. Practical Graph Isomorphism. Congressus Numerantium,9Vol. 30 (1981), pp. 45-87.1011[2] Leon, Jeffrey. Permutation Group Algorithms Based on Partitions, I:12Theory and Algorithms. J. Symbolic Computation, Vol. 12 (1991), pp.13533-583.1415"""1617#*****************************************************************************18# Copyright (C) 2006 - 2011 Robert L. Miller <[email protected]>19#20# Distributed under the terms of the GNU General Public License (GPL)21# http://www.gnu.org/licenses/22#*****************************************************************************2324include 'data_structures_pyx.pxi' # includes bitsets2526def set_stab_py(generators, sett, relab=False):27r"""28Compute the setwise stabilizer of a subset of [0..n-1] in a subgroup of S_n.2930EXAMPLES::3132sage: from sage.groups.perm_gps.partn_ref.refinement_sets import set_stab_py3334Degree 4 examples3536A four-cycle::3738sage: set_stab_py([[1,2,3,0]], [0])39[]40sage: set_stab_py([[1,2,3,0]], [0,1])41[]42sage: set_stab_py([[1,2,3,0]], [0,1,2])43[]44sage: set_stab_py([[1,2,3,0]], [0,1,2,3])45[[1, 2, 3, 0]]46sage: set_stab_py([[1,2,3,0]], [0,2])47[[2, 3, 0, 1]]4849Symmetric group::5051sage: set_stab_py([[1,0,2,3],[1,2,3,0]], [0])52[[0, 1, 3, 2], [0, 2, 1, 3]]53sage: set_stab_py([[1,0,2,3],[1,2,3,0]], [0,1])54[[1, 0, 2, 3], [0, 1, 3, 2]]55sage: set_stab_py([[1,0,2,3],[1,2,3,0]], [0,1,2,3])56[[0, 1, 3, 2], [0, 2, 1, 3], [1, 0, 2, 3]]57sage: set_stab_py([[1,0,2,3],[1,2,3,0]], [0,3])58[[3, 1, 2, 0], [0, 2, 1, 3]]5960Klein 4-group::6162sage: set_stab_py([[1,0,2,3],[0,1,3,2]], [0])63[[0, 1, 3, 2]]64sage: set_stab_py([[1,0,2,3],[0,1,3,2]], [0,1])65[[0, 1, 3, 2], [1, 0, 2, 3]]66sage: set_stab_py([[1,0,2,3],[0,1,3,2]], [0,2])67[]6869Dihedral group::7071sage: set_stab_py([[1,2,3,0],[0,3,2,1]], [0])72[[0, 3, 2, 1]]73sage: set_stab_py([[1,2,3,0],[0,3,2,1]], [0,1])74[[1, 0, 3, 2]]75sage: set_stab_py([[1,2,3,0],[0,3,2,1]], [0,2])76[[2, 1, 0, 3], [0, 3, 2, 1]]77sage: set_stab_py([[1,2,3,0],[0,3,2,1]], [1])78[[2, 1, 0, 3]]79sage: set_stab_py([[1,2,3,0],[0,3,2,1]], [1,2,3])80[[0, 3, 2, 1]]8182Alternating group::8384sage: set_stab_py([[1,2,0,3],[0,2,3,1]], [0])85[[0, 2, 3, 1]]86sage: set_stab_py([[1,2,0,3],[0,2,3,1]], [1])87[[2, 1, 3, 0]]88sage: set_stab_py([[1,2,0,3],[0,2,3,1]], [2])89[[1, 3, 2, 0]]90sage: set_stab_py([[1,2,0,3],[0,2,3,1]], [3])91[[1, 2, 0, 3]]92sage: set_stab_py([[1,2,0,3],[0,2,3,1]], [0,1])93[[1, 0, 3, 2]]94sage: set_stab_py([[1,2,0,3],[0,2,3,1]], [0,2])95[[2, 3, 0, 1]]96sage: set_stab_py([[1,2,0,3],[0,2,3,1]], [0,3])97[[3, 2, 1, 0]]9899Larger degree examples100101Dihedral group of degree 5::102103sage: set_stab_py([[1,2,3,4,0],[0,4,3,2,1]], [])104[[0, 4, 3, 2, 1], [1, 0, 4, 3, 2]]105sage: set_stab_py([[1,2,3,4,0],[0,4,3,2,1]], [0])106[[0, 4, 3, 2, 1]]107sage: set_stab_py([[1,2,3,4,0],[0,4,3,2,1]], [0,2])108[[2, 1, 0, 4, 3]]109110Dihedral group of degree 6::111112sage: set_stab_py([[1,2,3,4,5,0],[0,5,4,3,2,1]], [])113[[0, 5, 4, 3, 2, 1], [1, 0, 5, 4, 3, 2]]114sage: set_stab_py([[1,2,3,4,5,0],[0,5,4,3,2,1]], [0])115[[0, 5, 4, 3, 2, 1]]116sage: set_stab_py([[1,2,3,4,5,0],[0,5,4,3,2,1]], [0,1])117[[1, 0, 5, 4, 3, 2]]118sage: set_stab_py([[1,2,3,4,5,0],[0,5,4,3,2,1]], [0,2])119[[2, 1, 0, 5, 4, 3]]120sage: set_stab_py([[1,2,3,4,5,0],[0,5,4,3,2,1]], [0,3])121[[0, 5, 4, 3, 2, 1], [3, 2, 1, 0, 5, 4]]122sage: set_stab_py([[1,2,3,4,5,0],[0,5,4,3,2,1]], [0,2,4])123[[2, 1, 0, 5, 4, 3], [4, 3, 2, 1, 0, 5]]124125Canonical labels::126127sage: set_stab_py([[0,2,1,4,3,5,8,7,6],[8,7,6,3,5,4,2,1,0]], [0,1,3,5,6], True)128([], [7, 8, 6, 3, 4, 5, 2, 0, 1])129sage: set_stab_py([[0,2,1,4,3,5,8,7,6],[8,7,6,3,5,4,2,1,0]], [0,3,5,6,8], True)130([], [2, 1, 0, 5, 4, 3, 7, 6, 8])131132"""133if len(generators) == 0:134return []135cdef int i, j, n = len(generators[0]), n_gens = len(generators)136cdef StabilizerChain *supergroup = SC_new(n)137cdef aut_gp_and_can_lab *stabilizer138cdef int *gens = <int *> sage_malloc(n*n_gens * sizeof(int))139cdef subset *subset_sett = <subset *> sage_malloc(sizeof(subset))140if gens is NULL or supergroup is NULL or subset_sett is NULL:141SC_dealloc(supergroup)142sage_free(gens)143sage_free(subset_sett)144raise MemoryError145bitset_init(&subset_sett.bits, n)146subset_sett.scratch = <int *> sage_malloc((3*n+1) * sizeof(int))147for i from 0 <= i < len(generators):148for j from 0 <= j < n:149gens[n*i + j] = generators[i][j]150if SC_insert(supergroup, 0, gens, n_gens):151SC_dealloc(supergroup)152sage_free(gens)153sage_free(subset_sett)154raise MemoryError155sage_free(gens)156bitset_clear(&subset_sett.bits)157for i in sett:158bitset_add(&subset_sett.bits, i)159stabilizer = set_stab(supergroup, subset_sett, relab)160SC_dealloc(supergroup)161bitset_free(&subset_sett.bits)162sage_free(subset_sett.scratch)163sage_free(subset_sett)164if stabilizer is NULL:165raise MemoryError166stab_gens = []167for i from 0 <= i < stabilizer.num_gens:168stab_gens.append([stabilizer.generators[i*n+j] for j from 0 <= j < n])169if relab:170relabeling = [stabilizer.relabeling[j] for j from 0 <= j < n]171deallocate_agcl_output(stabilizer)172if relab:173return stab_gens, relabeling174return stab_gens175176cdef aut_gp_and_can_lab *set_stab(StabilizerChain *supergroup, subset *sett, bint relab):177r"""178Computes the set stabilizer of ``sett`` within ``supergroup``. (Note that179``set`` is a reserved Python keyword.) If ``relab`` is specified then180computes the canonical label of the set under the action of the group.181"""182cdef aut_gp_and_can_lab *output183cdef int n = supergroup.degree184cdef PartitionStack *part = PS_new(n, 1)185if part is NULL:186return NULL187output = get_aut_gp_and_can_lab(<void *> sett, part, n,188&all_set_children_are_equivalent, &refine_set, &compare_sets, relab,189supergroup, NULL, NULL)190PS_dealloc(part)191if output is NULL:192return NULL193return output194195def sets_isom_py(generators, set1, set2):196r"""197Computes whether ``set1`` and ``set2`` are isomorphic under the action of198the group generated by the generators given in list form.199200EXAMPLES::201202sage: from sage.groups.perm_gps.partn_ref.refinement_sets import sets_isom_py203204Degree 3 examples205206Trivial group::207208sage: sets_isom_py([], [0,1,2], [0,1])209False210sage: sets_isom_py([], [0,1,2], [0,2,1])211[0, 1, 2]212sage: sets_isom_py([[0,1,2]], [0,1,2], [0,2,1])213[0, 1, 2]214sage: sets_isom_py([[0,1,2]], [0], [0])215[0, 1, 2]216sage: sets_isom_py([[0,1,2]], [0], [1])217False218sage: sets_isom_py([[0,1,2]], [0], [2])219False220sage: sets_isom_py([[0,1,2]], [0,1], [1,0])221[0, 1, 2]222223Three-cycle::224225sage: sets_isom_py([[1,2,0]], [0], [1])226[1, 2, 0]227sage: sets_isom_py([[1,2,0]], [0], [2])228[2, 0, 1]229sage: sets_isom_py([[1,2,0]], [0], [0])230[0, 1, 2]231sage: sets_isom_py([[1,2,0]], [0,1], [0])232False233sage: sets_isom_py([[1,2,0]], [0,1], [1])234False235sage: sets_isom_py([[1,2,0]], [0,1], [2])236False237sage: sets_isom_py([[1,2,0]], [0,1], [0,2])238[2, 0, 1]239sage: sets_isom_py([[1,2,0]], [0,1], [1,2])240[1, 2, 0]241sage: sets_isom_py([[1,2,0]], [0,1], [1,0])242[0, 1, 2]243sage: sets_isom_py([[1,2,0]], [0,2,1], [2,1,0])244[0, 1, 2]245246Transposition::247248sage: sets_isom_py([[1,0,2]], [0], [])249False250sage: sets_isom_py([[1,0,2]], [0], [1,2])251False252sage: sets_isom_py([[1,0,2]], [0], [1])253[1, 0, 2]254sage: sets_isom_py([[1,0,2]], [0], [0])255[0, 1, 2]256sage: sets_isom_py([[1,0,2]], [0,1], [2])257False258sage: sets_isom_py([[1,0,2]], [0,2], [1,2])259[1, 0, 2]260sage: sets_isom_py([[1,0,2]], [0], [2])261False262sage: sets_isom_py([[1,0,2]], [0,1], [1,2])263False264265Symmetric group S_3::266267sage: sets_isom_py([[1,0,2],[1,2,0]], [], [])268[0, 1, 2]269sage: sets_isom_py([[1,0,2],[1,2,0]], [0], [])270False271sage: sets_isom_py([[1,0,2],[1,2,0]], [0], [0])272[0, 1, 2]273sage: sets_isom_py([[1,0,2],[1,2,0]], [0], [1])274[1, 0, 2]275sage: sets_isom_py([[1,0,2],[1,2,0]], [0], [2])276[2, 0, 1]277sage: sets_isom_py([[1,0,2],[1,2,0]], [0,2], [2])278False279sage: sets_isom_py([[1,0,2],[1,2,0]], [0,2], [1,2])280[1, 0, 2]281sage: sets_isom_py([[1,0,2],[1,2,0]], [0,2], [0,1])282[0, 2, 1]283sage: sets_isom_py([[1,0,2],[1,2,0]], [0,2], [0,2])284[0, 1, 2]285sage: sets_isom_py([[1,0,2],[1,2,0]], [0,2], [0,1,2])286False287sage: sets_isom_py([[1,0,2],[1,2,0]], [0,2,1], [0,1,2])288[0, 1, 2]289290Degree 4 examples291292Trivial group::293294sage: sets_isom_py([[0,1,2,3]], [], [])295[0, 1, 2, 3]296sage: sets_isom_py([[0,1,2,3]], [0], [])297False298sage: sets_isom_py([[0,1,2,3]], [0], [1])299False300sage: sets_isom_py([[0,1,2,3]], [0], [2])301False302sage: sets_isom_py([[0,1,2,3]], [0], [3])303False304sage: sets_isom_py([[0,1,2,3]], [0], [0])305[0, 1, 2, 3]306sage: sets_isom_py([[0,1,2,3]], [0,1], [1,2])307False308sage: sets_isom_py([[0,1,2,3]], [0,1], [0,1])309[0, 1, 2, 3]310sage: sets_isom_py([[0,1,2,3]], [0,1,2,3], [0,1])311False312sage: sets_isom_py([[0,1,2,3]], [0,1,2,3], [0,1,2,3])313[0, 1, 2, 3]314315Four-cycle::316317sage: sets_isom_py([[1,2,3,0]], [0,1,2,3], [0,1,2,3])318[0, 1, 2, 3]319sage: sets_isom_py([[1,2,3,0]], [], [])320[0, 1, 2, 3]321sage: sets_isom_py([[1,2,3,0]], [0], [0])322[0, 1, 2, 3]323sage: sets_isom_py([[1,2,3,0]], [0], [1])324[1, 2, 3, 0]325sage: sets_isom_py([[1,2,3,0]], [0], [2])326[2, 3, 0, 1]327sage: sets_isom_py([[1,2,3,0]], [0], [3])328[3, 0, 1, 2]329sage: sets_isom_py([[1,2,3,0]], [0,1], [3])330False331sage: sets_isom_py([[1,2,3,0]], [0,1], [])332False333sage: sets_isom_py([[1,2,3,0]], [0,1], [1,2,3])334False335sage: sets_isom_py([[1,2,3,0]], [0,1], [1,2])336[1, 2, 3, 0]337sage: sets_isom_py([[1,2,3,0]], [0,1], [2,3])338[2, 3, 0, 1]339sage: sets_isom_py([[1,2,3,0]], [0,1], [0,3])340[3, 0, 1, 2]341sage: sets_isom_py([[1,2,3,0]], [0,2], [0,2])342[0, 1, 2, 3]343sage: sets_isom_py([[1,2,3,0]], [0,2], [1,3])344[3, 0, 1, 2]345sage: sets_isom_py([[1,2,3,0]], [0,1,2], [1,2,3])346[1, 2, 3, 0]347sage: sets_isom_py([[1,2,3,0]], [0,1,2], [0,2,3])348[2, 3, 0, 1]349sage: sets_isom_py([[1,2,3,0]], [0,1,2], [0,1,3])350[3, 0, 1, 2]351sage: sets_isom_py([[1,2,3,0]], [0,1,2], [0,1,2])352[0, 1, 2, 3]353354Two transpositions::355356sage: from sage.groups.perm_gps.partn_ref.refinement_sets import sets_isom_py357sage: sets_isom_py([[2,3,0,1]], [0], [2])358[2, 3, 0, 1]359sage: sets_isom_py([[2,3,0,1]], [1], [3])360[2, 3, 0, 1]361sage: sets_isom_py([[2,3,0,1]], [1], [1])362[0, 1, 2, 3]363sage: sets_isom_py([[2,3,0,1]], [1], [2])364False365sage: sets_isom_py([[2,3,0,1]], [0,3], [1,2])366[2, 3, 0, 1]367sage: sets_isom_py([[2,3,0,1]], [0,3], [3,0])368[0, 1, 2, 3]369sage: sets_isom_py([[2,3,0,1]], [0,1,3], [0,2,3])370False371sage: sets_isom_py([[2,3,0,1]], [0,1,3], [1,2,3])372[2, 3, 0, 1]373374375"""376from sage.misc.misc import uniq377set1 = uniq(set1)378set2 = uniq(set2)379if len(generators) == 0:380if set1 == set2:381return range(max(set1)+1)382else:383return False384cdef int i, j, n = len(generators[0]), n_gens = len(generators)385cdef StabilizerChain *supergroup = SC_new(n)386cdef int *gens = <int *> sage_malloc(n*n_gens * sizeof(int))387cdef int *isom = <int *> sage_malloc(n * sizeof(int))388cdef subset *subset_sett1 = <subset *> sage_malloc(sizeof(subset))389cdef subset *subset_sett2 = <subset *> sage_malloc(sizeof(subset))390bitset_init(&subset_sett1.bits, n)391bitset_init(&subset_sett2.bits, n)392subset_sett1.scratch = <int *> sage_malloc((3*n+1) * sizeof(int))393subset_sett2.scratch = <int *> sage_malloc((3*n+1) * sizeof(int))394for i from 0 <= i < len(generators):395for j from 0 <= j < n:396gens[n*i + j] = generators[i][j]397if SC_insert(supergroup, 0, gens, n_gens):398raise MemoryError399sage_free(gens)400bitset_clear(&subset_sett1.bits)401bitset_clear(&subset_sett2.bits)402for i in set1:403bitset_add(&subset_sett1.bits, i)404for i in set2:405bitset_add(&subset_sett2.bits, i)406cdef bint isomorphic = sets_isom(supergroup, subset_sett1, subset_sett2, isom)407SC_dealloc(supergroup)408bitset_free(&subset_sett1.bits)409bitset_free(&subset_sett2.bits)410sage_free(subset_sett1.scratch)411sage_free(subset_sett2.scratch)412sage_free(subset_sett1)413sage_free(subset_sett2)414if isomorphic:415output_py = [isom[i] for i from 0 <= i < n]416else:417output_py = False418sage_free(isom)419return output_py420421cdef int sets_isom(StabilizerChain *supergroup, subset *set1, subset *set2, int *isom) except -1:422r"""423Underlying C function for testing two sets for isomorphism.424"""425cdef int n = supergroup.degree426cdef bint x427cdef PartitionStack *part = PS_new(n, 1)428if part is NULL:429raise MemoryError430x = double_coset(set1, set2, part, NULL, n,431&all_set_children_are_equivalent, &refine_set, &compare_sets,432supergroup, NULL, isom)433PS_dealloc(part)434return x435436cdef bint all_set_children_are_equivalent(PartitionStack *PS, void *S):437return 0438439cdef int refine_set(PartitionStack *PS, void *S, int *cells_to_refine_by, int ctrb_len):440"""441Given a set S, refine the partition stack PS so that each cell contains442elements which are all either in the set or not in the set. If the depth is443positive we do nothing since the cells will have already been split at an444earlier level.445"""446if PS.depth > 0:447return 0448cdef subset *subset1 = <subset *> S449cdef int *scratch = subset1.scratch450cdef int start, i, n = PS.degree, x451start = 0452while start < n:453i = 0454while 1:455scratch[i] = bitset_in(&subset1.bits, PS.entries[start+i])456if PS.levels[start+i] <= PS.depth:457break458i += 1459sort_by_function(PS, start, scratch)460start += i+1461return 0462463cdef inline int _bint_cmp(bint a, bint b):464return (<int> b) - (<int> a)465466cdef int compare_sets(int *gamma_1, int *gamma_2, void *S1, void *S2, int degree):467r"""468Compare two sets according to the lexicographic order.469"""470cdef subset *subset1 = <subset *> S1471cdef subset *subset2 = <subset *> S2472cdef bitset_s set1 = subset1.bits473cdef bitset_s set2 = subset2.bits474cdef int i, j475for i from 0 <= i < degree:476j = _bint_cmp(bitset_in(&set1, gamma_1[i]), bitset_in(&set2, gamma_2[i]))477if j != 0: return j478return 0479480cdef void *allocate_subset(int n):481r"""482Allocates a subset struct of degree n.483"""484cdef subset *set1 = <subset *> sage_malloc(sizeof(subset))485cdef int *scratch = <int *> sage_malloc((3*n+1) * sizeof(int))486if set1 is NULL or scratch is NULL:487sage_free(set1)488sage_free(scratch)489return NULL490try:491bitset_init(&set1.bits, n)492except MemoryError:493sage_free(set1)494sage_free(scratch)495return NULL496set1.scratch = scratch497return <void *> set1498499cdef void free_subset(void *child):500r"""501Deallocates a subset struct.502"""503cdef subset *set1 = <subset *> child504if set1 is not NULL:505sage_free(set1.scratch)506bitset_free(&set1.bits)507sage_free(set1)508509cdef void *allocate_sgd(int degree):510r"""511Allocates the data part of an iterator which generates augmentations, i.e.,512elements to add to the set.513"""514cdef subset_generator_data *sgd = <subset_generator_data *> sage_malloc(sizeof(subset_generator_data))515sgd.orbits = OP_new(degree)516if sgd is NULL or sgd.orbits is NULL:517deallocate_sgd(sgd)518return NULL519return <void *> sgd520521cdef void deallocate_sgd(void *data):522r"""523Deallocates the data part of the augmentation iterator.524"""525cdef subset_generator_data *sgd = <subset_generator_data *> data526if sgd is not NULL:527OP_dealloc(sgd.orbits)528sage_free(sgd)529530cdef void *subset_generator_next(void *data, int *degree, bint *mem_err):531r"""532Returns the next element to consider adding to the set.533"""534cdef subset_generator_data *sgd = <subset_generator_data *> data535while 1:536sgd.cur_point += 1537if sgd.cur_point == sgd.orbits.degree:538break539if OP_find(sgd.orbits, sgd.cur_point) == sgd.cur_point and \540not bitset_in(&sgd.bits, sgd.cur_point):541break542if sgd.cur_point == sgd.orbits.degree or mem_err[0]:543return NULL544return <void *> &sgd.cur_point545546cdef int generate_child_subsets(void *S, aut_gp_and_can_lab *group, iterator *child_iterator):547r"""548Sets up an iterator of augmentations, i.e., elements to add to the given set.549"""550cdef subset *subset1 = <subset *> S551cdef bitset_s set1 = subset1.bits552cdef int i, j, n = group.group.degree553cdef subset_generator_data *sgd = <subset_generator_data *> child_iterator.data554OP_clear(sgd.orbits)555for i from 0 <= i < group.num_gens:556for j from 0 <= j < n:557OP_join(sgd.orbits, j, group.generators[n*i + j])558i = bitset_first(&subset1.bits)559j = bitset_next(&subset1.bits, i+1)560while j != -1:561OP_join(sgd.orbits, i, j)562j = bitset_next(&subset1.bits, j+1)563sgd.cur_point = -1564sgd.bits = subset1.bits565return 0566567cdef void *apply_subset_aug(void *parent, void *aug, void *child, int *degree, bint *mem_err):568r"""569Adds the element represented by ``aug`` to ``parent``, storing the result to570``child``.571"""572cdef subset *set1 = <subset *> child, *par_set = <subset *> parent573cdef bitset_s parbits = par_set.bits574cdef int add_pt = (<int *> aug)[0], n = parbits.size575bitset_copy(&set1.bits, &parbits)576bitset_add(&set1.bits, add_pt)577degree[0] = n578return <void *> set1579580cdef void free_subset_aug(void *aug):581return582583cdef void *canonical_set_parent(void *child, void *parent, int *permutation, int *degree, bint *mem_err):584r"""585Determines the canonical parent of the set ``child`` by applying586``permutation``, deleting the largest element in lexicographic order, and587storing the result to ``parent``.588"""589cdef subset *set1 = <subset *> child590cdef bitset_t can_par591cdef int i, max_in_can_lab, max_loc, n = set1.bits.size592cdef subset *par593if parent is NULL:594par = <subset *> allocate_subset(n)595if par is NULL:596mem_err[0] = 1597else:598par = <subset *> parent599if mem_err[0]:600return NULL601i = bitset_first(&set1.bits)602max_in_can_lab = permutation[i]603max_loc = i604while i != -1:605if max_in_can_lab < permutation[i]:606max_in_can_lab = permutation[i]607max_loc = i608i = bitset_next(&set1.bits, i+1)609bitset_copy(&par.bits, &set1.bits)610bitset_discard(&par.bits, max_loc)611degree[0] = n612return <void *> par613614cdef iterator *allocate_subset_gen(int degree, int max_size):615r"""616Allocates the generator of subsets.617"""618cdef iterator *subset_gen = <iterator *> sage_malloc(sizeof(iterator))619if subset_gen is not NULL:620if allocate_subset_gen_2(degree, max_size, subset_gen):621sage_free(subset_gen)622subset_gen = NULL623return subset_gen624625cdef int allocate_subset_gen_2(int degree, int max_size, iterator *it):626r"""627Given an already allocated iterator, allocates the generator of subsets.628"""629cdef canonical_generator_data *cgd = allocate_cgd(max_size + 1, degree)630if cgd is NULL:631return 1632cdef int i, j633for i from 0 <= i < max_size + 1:634cgd.object_stack[i] = allocate_subset(degree)635cgd.parent_stack[i] = allocate_subset(degree)636cgd.iterator_stack[i].data = allocate_sgd(degree)637cgd.iterator_stack[i].next = &subset_generator_next638if cgd.iterator_stack[i].data is NULL or \639cgd.object_stack[i] is NULL or \640cgd.parent_stack[i] is NULL:641for j from 0 <= j <= i:642deallocate_sgd(cgd.iterator_stack[i].data)643free_subset(cgd.object_stack[i])644free_subset(cgd.parent_stack[i])645deallocate_cgd(cgd)646return 1647it.data = <void *> cgd648it.next = &canonical_generator_next649return 0650651cdef void free_subset_gen(iterator *subset_gen):652r"""653Frees the iterator of subsets.654"""655if subset_gen is NULL: return656cdef canonical_generator_data *cgd = <canonical_generator_data *> subset_gen.data657deallocate_cgd(cgd)658sage_free(subset_gen)659660cdef iterator *setup_set_gen(iterator *subset_gen, int degree, int max_size):661r"""662Initiates the iterator of subsets.663"""664cdef subset *empty_set665cdef iterator *subset_iterator = setup_canonical_generator(degree,666&all_set_children_are_equivalent,667&refine_set,668&compare_sets,669&generate_child_subsets,670&apply_subset_aug,671&free_subset,672&deallocate_sgd,673&free_subset_aug,674&canonical_set_parent,675max_size+1, 0, subset_gen)676if subset_iterator is not NULL:677empty_set = <subset *> (<canonical_generator_data *> subset_gen.data).object_stack[0]678bitset_clear(&empty_set.bits)679return subset_iterator680681def sets_modulo_perm_group(list generators, int max_size, bint indicate_mem_err = 1):682r"""683Given generators of a permutation group, list subsets up to permutations in684the group.685686INPUT:687688- ``generators`` - (list of lists) list of generators in list form689- ``max_size`` - (int) maximum size of subsets to be generated690- ``indicate_mem_err`` - (bool) whether to raise an error691if we run out of memory, or simply append a MemoryError692instance to the end of the output693694EXAMPLES::695696sage: from sage.groups.perm_gps.partn_ref.refinement_sets import sets_modulo_perm_group697sage: sets_modulo_perm_group([], 0)698[[]]699sage: sets_modulo_perm_group([], 1)700[[0], []]701sage: sets_modulo_perm_group([], 2)702[[0, 1], [0], []]703sage: sets_modulo_perm_group([], 3)704[[0, 1, 2], [0, 1], [0], []]705sage: sets_modulo_perm_group([], 4)706[[0, 1, 2, 3], [0, 1, 2], [0, 1], [0], []]707sage: len(sets_modulo_perm_group([], 99))708100709710::711712sage: sets_modulo_perm_group([[1,2,0]], 4)713[[0, 1, 2], [0, 1], [0], []]714sage: sets_modulo_perm_group([[1,2,0]], 3)715[[0, 1, 2], [0, 1], [0], []]716sage: sets_modulo_perm_group([[1,2,0]], 2)717[[0, 1], [0], []]718sage: sets_modulo_perm_group([[1,2,0]], 1)719[[0], []]720sage: sets_modulo_perm_group([[1,2,0]], 0)721[[]]722sage: sets_modulo_perm_group([[0,1,2]], 3)723[[0, 1, 2], [0, 1], [0, 2], [0], [1, 2], [1], [2], []]724sage: sets_modulo_perm_group([[1,0,2]], 3)725[[0, 1, 2], [0, 1], [0, 2], [0], [2], []]726sage: sets_modulo_perm_group([[1,0,2],[1,2,0]], 3)727[[0, 1, 2], [0, 1], [1], []]728729::730731sage: sets_modulo_perm_group([[1,2,3,0]], 4)732[[0, 1, 2, 3], [0, 1, 2], [0, 1], [0, 2], [0], []]733sage: sets_modulo_perm_group([[1,2,3,0]], 5)734[[0, 1, 2, 3], [0, 1, 2], [0, 1], [0, 2], [0], []]735sage: sets_modulo_perm_group([[1,2,3,0]], 3)736[[0, 1, 2], [0, 1], [0, 2], [0], []]737sage: sets_modulo_perm_group([[1,2,3,0]], 2)738[[0, 1], [0, 2], [0], []]739sage: sets_modulo_perm_group([[1,2,3,0]], 1)740[[0], []]741sage: sets_modulo_perm_group([[1,2,3,0]], 0)742[[]]743sage: sets_modulo_perm_group([[0,1,3,2],[1,0,2,3]], 4)744[[0, 1, 2, 3], [0, 1, 2], [0, 1], [0, 2, 3], [0, 2], [0], [2, 3], [2], []]745sage: sets_modulo_perm_group([[1,0,2,3],[1,2,0,3]], 4)746[[0, 1, 2, 3], [0, 1, 2], [0, 1, 3], [0, 1], [1, 3], [1], [3], []]747sage: sets_modulo_perm_group([[1,2,0,3],[0,2,3,1]], 4)748[[0, 1, 2, 3], [0, 1, 2], [0, 1], [1], []]749sage: sets_modulo_perm_group([[1,0,2,3],[1,2,3,0]], 4)750[[0, 1, 2, 3], [0, 1, 2], [1, 2], [2], []]751sage: L = list(powerset(range(4)))752sage: L.sort()753sage: L == sorted(sets_modulo_perm_group([[0,1,2,3]], 4))754True755756::757758sage: sets_modulo_perm_group([[1,2,3,4,0]], 5)759[[0, 1, 2, 3, 4], [0, 1, 2, 3], [0, 1, 2], [0, 1], [0, 2, 3], [0, 2], [0], []]760sage: sets_modulo_perm_group([[1,0,2,3,4],[0,1,3,4,2]], 5)761[[0, 1, 2, 3, 4], [0, 1, 2, 3], [0, 1, 2], [0, 1], [0, 2, 3, 4], [0, 2, 3], [0, 2], [0], [2, 3, 4], [2, 3], [2], []]762sage: L = list(powerset(range(5)))763sage: L.sort()764sage: L == sorted(sets_modulo_perm_group([[0,1,2,3,4]], 5))765True766sage: sets_modulo_perm_group([[1,0,2,3,4],[1,2,3,4,0]], 5)767[[0, 1, 2, 3, 4], [0, 1, 2, 3], [1, 2, 3], [2, 3], [3], []]768sage: sets_modulo_perm_group([[1,2,0,3,4],[0,2,3,1,4],[0,1,3,4,2]], 5)769[[0, 1, 2, 3, 4], [0, 1, 2, 3], [1, 2, 3], [1, 2], [2], []]770771::772773sage: X = sets_modulo_perm_group([[1,2,3,4,5,0]], 6)774sage: [a for a in X if len(a) == 0]775[[]]776sage: [a for a in X if len(a) == 1]777[[0]]778sage: [a for a in X if len(a) == 2]779[[0, 1], [0, 2], [0, 3]]780sage: [a for a in X if len(a) == 3]781[[0, 1, 2], [0, 1, 3], [0, 2, 3], [0, 2, 4]]782sage: [a for a in X if len(a) == 4]783[[0, 1, 2, 3], [0, 1, 3, 4], [0, 2, 3, 4]]784sage: [a for a in X if len(a) == 5]785[[0, 1, 2, 3, 4]]786sage: [a for a in X if len(a) == 6]787[[0, 1, 2, 3, 4, 5]]788789::790791sage: X = sets_modulo_perm_group([[0,2,1,4,3,5,8,7,6],[8,7,6,3,5,4,2,1,0]], 9)792sage: len(X)79374794795"""796cdef list out_list = []797cdef int i798if max_size == 0:799return [[]]800if len(generators) == 0:801ll = []802for i in range(max_size,-1,-1):803ll.append(range(i))804return ll805cdef int n = len(generators[0]), n_gens = len(generators)806cdef iterator *subset_iterator807cdef subset *thing808809cdef StabilizerChain *group = SC_new(n)810cdef int *gens = <int *> sage_malloc(n*n_gens * sizeof(int))811if group is NULL or gens is NULL:812SC_dealloc(group)813sage_free(gens)814raise MemoryError815for i from 0 <= i < len(generators):816for j from 0 <= j < n:817gens[n*i + j] = generators[i][j]818if SC_insert(group, 0, gens, n_gens):819SC_dealloc(group)820sage_free(gens)821raise MemoryError822sage_free(gens)823824cdef iterator *subset_gen = allocate_subset_gen(n, max_size)825if subset_gen is NULL:826SC_dealloc(group)827raise MemoryError828subset_iterator = setup_set_gen(subset_gen, n, max_size)829cdef bint mem_err = 0830if subset_iterator is NULL:831SC_dealloc(group)832free_subset_gen(subset_gen)833mem_err = 1834else:835start_canonical_generator(group, NULL, n, subset_gen)836while not mem_err:837thing = <subset *> subset_iterator.next(subset_iterator.data, NULL, &mem_err)838if thing is NULL: break839out_list.append( bitset_list(&thing.bits) )840free_subset_gen(subset_gen)841SC_dealloc(group)842if mem_err:843if indicate_mem_err:844raise MemoryError845else:846out_list.append(MemoryError())847return out_list848849850851852853854855856