Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
r""" Partition backtrack functions for sets
EXAMPLES::
sage: import sage.groups.perm_gps.partn_ref.refinement_sets
REFERENCE:
[1] McKay, Brendan D. Practical Graph Isomorphism. Congressus Numerantium, Vol. 30 (1981), pp. 45-87.
[2] Leon, Jeffrey. Permutation Group Algorithms Based on Partitions, I: Theory and Algorithms. J. Symbolic Computation, Vol. 12 (1991), pp. 533-583.
"""
#***************************************************************************** # Copyright (C) 2006 - 2011 Robert L. Miller <rlmillster@gmail.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ #*****************************************************************************
from .data_structures cimport * from .double_coset cimport double_coset include "sage/data_structures/bitset.pxi"
r""" Compute the setwise stabilizer of a subset of [0..n-1] in a subgroup of S_n.
EXAMPLES::
sage: from sage.groups.perm_gps.partn_ref.refinement_sets import set_stab_py
Degree 4 examples
A four-cycle::
sage: set_stab_py([[1,2,3,0]], [0]) [] sage: set_stab_py([[1,2,3,0]], [0,1]) [] sage: set_stab_py([[1,2,3,0]], [0,1,2]) [] sage: set_stab_py([[1,2,3,0]], [0,1,2,3]) [[1, 2, 3, 0]] sage: set_stab_py([[1,2,3,0]], [0,2]) [[2, 3, 0, 1]]
Symmetric group::
sage: set_stab_py([[1,0,2,3],[1,2,3,0]], [0]) [[0, 1, 3, 2], [0, 2, 1, 3]] sage: set_stab_py([[1,0,2,3],[1,2,3,0]], [0,1]) [[1, 0, 2, 3], [0, 1, 3, 2]] sage: set_stab_py([[1,0,2,3],[1,2,3,0]], [0,1,2,3]) [[0, 1, 3, 2], [0, 2, 1, 3], [1, 0, 2, 3]] sage: set_stab_py([[1,0,2,3],[1,2,3,0]], [0,3]) [[3, 1, 2, 0], [0, 2, 1, 3]]
Klein 4-group::
sage: set_stab_py([[1,0,2,3],[0,1,3,2]], [0]) [[0, 1, 3, 2]] sage: set_stab_py([[1,0,2,3],[0,1,3,2]], [0,1]) [[0, 1, 3, 2], [1, 0, 2, 3]] sage: set_stab_py([[1,0,2,3],[0,1,3,2]], [0,2]) []
Dihedral group::
sage: set_stab_py([[1,2,3,0],[0,3,2,1]], [0]) [[0, 3, 2, 1]] sage: set_stab_py([[1,2,3,0],[0,3,2,1]], [0,1]) [[1, 0, 3, 2]] sage: set_stab_py([[1,2,3,0],[0,3,2,1]], [0,2]) [[2, 1, 0, 3], [0, 3, 2, 1]] sage: set_stab_py([[1,2,3,0],[0,3,2,1]], [1]) [[2, 1, 0, 3]] sage: set_stab_py([[1,2,3,0],[0,3,2,1]], [1,2,3]) [[0, 3, 2, 1]]
Alternating group::
sage: set_stab_py([[1,2,0,3],[0,2,3,1]], [0]) [[0, 2, 3, 1]] sage: set_stab_py([[1,2,0,3],[0,2,3,1]], [1]) [[2, 1, 3, 0]] sage: set_stab_py([[1,2,0,3],[0,2,3,1]], [2]) [[1, 3, 2, 0]] sage: set_stab_py([[1,2,0,3],[0,2,3,1]], [3]) [[1, 2, 0, 3]] sage: set_stab_py([[1,2,0,3],[0,2,3,1]], [0,1]) [[1, 0, 3, 2]] sage: set_stab_py([[1,2,0,3],[0,2,3,1]], [0,2]) [[2, 3, 0, 1]] sage: set_stab_py([[1,2,0,3],[0,2,3,1]], [0,3]) [[3, 2, 1, 0]]
Larger degree examples
Dihedral group of degree 5::
sage: set_stab_py([[1,2,3,4,0],[0,4,3,2,1]], []) [[0, 4, 3, 2, 1], [1, 0, 4, 3, 2]] sage: set_stab_py([[1,2,3,4,0],[0,4,3,2,1]], [0]) [[0, 4, 3, 2, 1]] sage: set_stab_py([[1,2,3,4,0],[0,4,3,2,1]], [0,2]) [[2, 1, 0, 4, 3]]
Dihedral group of degree 6::
sage: set_stab_py([[1,2,3,4,5,0],[0,5,4,3,2,1]], []) [[0, 5, 4, 3, 2, 1], [1, 0, 5, 4, 3, 2]] sage: set_stab_py([[1,2,3,4,5,0],[0,5,4,3,2,1]], [0]) [[0, 5, 4, 3, 2, 1]] sage: set_stab_py([[1,2,3,4,5,0],[0,5,4,3,2,1]], [0,1]) [[1, 0, 5, 4, 3, 2]] sage: set_stab_py([[1,2,3,4,5,0],[0,5,4,3,2,1]], [0,2]) [[2, 1, 0, 5, 4, 3]] sage: set_stab_py([[1,2,3,4,5,0],[0,5,4,3,2,1]], [0,3]) [[0, 5, 4, 3, 2, 1], [3, 2, 1, 0, 5, 4]] sage: set_stab_py([[1,2,3,4,5,0],[0,5,4,3,2,1]], [0,2,4]) [[2, 1, 0, 5, 4, 3], [4, 3, 2, 1, 0, 5]]
Canonical labels::
sage: 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) ([], [7, 8, 6, 3, 4, 5, 2, 0, 1]) sage: 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) ([], [2, 1, 0, 5, 4, 3, 7, 6, 8])
""" return [] cdef aut_gp_and_can_lab *stabilizer SC_dealloc(supergroup) sig_free(gens) sig_free(subset_sett) raise MemoryError SC_dealloc(supergroup) sig_free(gens) sig_free(subset_sett) raise MemoryError raise MemoryError
cdef aut_gp_and_can_lab *set_stab(StabilizerChain *supergroup, subset *sett, bint relab): r""" Computes the set stabilizer of ``sett`` within ``supergroup``. (Note that ``set`` is a reserved Python keyword.) If ``relab`` is specified then computes the canonical label of the set under the action of the group. """ cdef aut_gp_and_can_lab *output return NULL &all_set_children_are_equivalent, &refine_set, &compare_sets, relab, supergroup, NULL, NULL) return NULL
r""" Computes whether ``set1`` and ``set2`` are isomorphic under the action of the group generated by the generators given in list form.
EXAMPLES::
sage: from sage.groups.perm_gps.partn_ref.refinement_sets import sets_isom_py
Degree 3 examples
Trivial group::
sage: sets_isom_py([], [0,1,2], [0,1]) False sage: sets_isom_py([], [0,1,2], [0,2,1]) [0, 1, 2] sage: sets_isom_py([[0,1,2]], [0,1,2], [0,2,1]) [0, 1, 2] sage: sets_isom_py([[0,1,2]], [0], [0]) [0, 1, 2] sage: sets_isom_py([[0,1,2]], [0], [1]) False sage: sets_isom_py([[0,1,2]], [0], [2]) False sage: sets_isom_py([[0,1,2]], [0,1], [1,0]) [0, 1, 2]
Three-cycle::
sage: sets_isom_py([[1,2,0]], [0], [1]) [1, 2, 0] sage: sets_isom_py([[1,2,0]], [0], [2]) [2, 0, 1] sage: sets_isom_py([[1,2,0]], [0], [0]) [0, 1, 2] sage: sets_isom_py([[1,2,0]], [0,1], [0]) False sage: sets_isom_py([[1,2,0]], [0,1], [1]) False sage: sets_isom_py([[1,2,0]], [0,1], [2]) False sage: sets_isom_py([[1,2,0]], [0,1], [0,2]) [2, 0, 1] sage: sets_isom_py([[1,2,0]], [0,1], [1,2]) [1, 2, 0] sage: sets_isom_py([[1,2,0]], [0,1], [1,0]) [0, 1, 2] sage: sets_isom_py([[1,2,0]], [0,2,1], [2,1,0]) [0, 1, 2]
Transposition::
sage: sets_isom_py([[1,0,2]], [0], []) False sage: sets_isom_py([[1,0,2]], [0], [1,2]) False sage: sets_isom_py([[1,0,2]], [0], [1]) [1, 0, 2] sage: sets_isom_py([[1,0,2]], [0], [0]) [0, 1, 2] sage: sets_isom_py([[1,0,2]], [0,1], [2]) False sage: sets_isom_py([[1,0,2]], [0,2], [1,2]) [1, 0, 2] sage: sets_isom_py([[1,0,2]], [0], [2]) False sage: sets_isom_py([[1,0,2]], [0,1], [1,2]) False
Symmetric group S_3::
sage: sets_isom_py([[1,0,2],[1,2,0]], [], []) [0, 1, 2] sage: sets_isom_py([[1,0,2],[1,2,0]], [0], []) False sage: sets_isom_py([[1,0,2],[1,2,0]], [0], [0]) [0, 1, 2] sage: sets_isom_py([[1,0,2],[1,2,0]], [0], [1]) [1, 0, 2] sage: sets_isom_py([[1,0,2],[1,2,0]], [0], [2]) [2, 0, 1] sage: sets_isom_py([[1,0,2],[1,2,0]], [0,2], [2]) False sage: sets_isom_py([[1,0,2],[1,2,0]], [0,2], [1,2]) [1, 0, 2] sage: sets_isom_py([[1,0,2],[1,2,0]], [0,2], [0,1]) [0, 2, 1] sage: sets_isom_py([[1,0,2],[1,2,0]], [0,2], [0,2]) [0, 1, 2] sage: sets_isom_py([[1,0,2],[1,2,0]], [0,2], [0,1,2]) False sage: sets_isom_py([[1,0,2],[1,2,0]], [0,2,1], [0,1,2]) [0, 1, 2]
Degree 4 examples
Trivial group::
sage: sets_isom_py([[0,1,2,3]], [], []) [0, 1, 2, 3] sage: sets_isom_py([[0,1,2,3]], [0], []) False sage: sets_isom_py([[0,1,2,3]], [0], [1]) False sage: sets_isom_py([[0,1,2,3]], [0], [2]) False sage: sets_isom_py([[0,1,2,3]], [0], [3]) False sage: sets_isom_py([[0,1,2,3]], [0], [0]) [0, 1, 2, 3] sage: sets_isom_py([[0,1,2,3]], [0,1], [1,2]) False sage: sets_isom_py([[0,1,2,3]], [0,1], [0,1]) [0, 1, 2, 3] sage: sets_isom_py([[0,1,2,3]], [0,1,2,3], [0,1]) False sage: sets_isom_py([[0,1,2,3]], [0,1,2,3], [0,1,2,3]) [0, 1, 2, 3]
Four-cycle::
sage: sets_isom_py([[1,2,3,0]], [0,1,2,3], [0,1,2,3]) [0, 1, 2, 3] sage: sets_isom_py([[1,2,3,0]], [], []) [0, 1, 2, 3] sage: sets_isom_py([[1,2,3,0]], [0], [0]) [0, 1, 2, 3] sage: sets_isom_py([[1,2,3,0]], [0], [1]) [1, 2, 3, 0] sage: sets_isom_py([[1,2,3,0]], [0], [2]) [2, 3, 0, 1] sage: sets_isom_py([[1,2,3,0]], [0], [3]) [3, 0, 1, 2] sage: sets_isom_py([[1,2,3,0]], [0,1], [3]) False sage: sets_isom_py([[1,2,3,0]], [0,1], []) False sage: sets_isom_py([[1,2,3,0]], [0,1], [1,2,3]) False sage: sets_isom_py([[1,2,3,0]], [0,1], [1,2]) [1, 2, 3, 0] sage: sets_isom_py([[1,2,3,0]], [0,1], [2,3]) [2, 3, 0, 1] sage: sets_isom_py([[1,2,3,0]], [0,1], [0,3]) [3, 0, 1, 2] sage: sets_isom_py([[1,2,3,0]], [0,2], [0,2]) [0, 1, 2, 3] sage: sets_isom_py([[1,2,3,0]], [0,2], [1,3]) [3, 0, 1, 2] sage: sets_isom_py([[1,2,3,0]], [0,1,2], [1,2,3]) [1, 2, 3, 0] sage: sets_isom_py([[1,2,3,0]], [0,1,2], [0,2,3]) [2, 3, 0, 1] sage: sets_isom_py([[1,2,3,0]], [0,1,2], [0,1,3]) [3, 0, 1, 2] sage: sets_isom_py([[1,2,3,0]], [0,1,2], [0,1,2]) [0, 1, 2, 3]
Two transpositions::
sage: from sage.groups.perm_gps.partn_ref.refinement_sets import sets_isom_py sage: sets_isom_py([[2,3,0,1]], [0], [2]) [2, 3, 0, 1] sage: sets_isom_py([[2,3,0,1]], [1], [3]) [2, 3, 0, 1] sage: sets_isom_py([[2,3,0,1]], [1], [1]) [0, 1, 2, 3] sage: sets_isom_py([[2,3,0,1]], [1], [2]) False sage: sets_isom_py([[2,3,0,1]], [0,3], [1,2]) [2, 3, 0, 1] sage: sets_isom_py([[2,3,0,1]], [0,3], [3,0]) [0, 1, 2, 3] sage: sets_isom_py([[2,3,0,1]], [0,1,3], [0,2,3]) False sage: sets_isom_py([[2,3,0,1]], [0,1,3], [1,2,3]) [2, 3, 0, 1]
""" else: raise MemoryError else:
cdef int sets_isom(StabilizerChain *supergroup, subset *set1, subset *set2, int *isom) except -1: r""" Underlying C function for testing two sets for isomorphism. """ cdef bint x raise MemoryError &all_set_children_are_equivalent, &refine_set, &compare_sets, supergroup, NULL, isom)
cdef bint all_set_children_are_equivalent(PartitionStack *PS, void *S):
cdef int refine_set(PartitionStack *PS, void *S, int *cells_to_refine_by, int ctrb_len): """ Given a set S, refine the partition stack PS so that each cell contains elements which are all either in the set or not in the set. If the depth is positive we do nothing since the cells will have already been split at an earlier level. """
cdef inline int _bint_cmp(bint a, bint b):
cdef int compare_sets(int *gamma_1, int *gamma_2, void *S1, void *S2, int degree): r""" Compare two sets according to the lexicographic order. """ cdef int i, j
cdef void *allocate_subset(int n): r""" Allocates a subset struct of degree n. """ sig_free(set1) sig_free(scratch) return NULL except MemoryError: sig_free(set1) sig_free(scratch) return NULL
cdef void free_subset(void *child): r""" Deallocates a subset struct. """
cdef void *allocate_sgd(int degree): r""" Allocates the data part of an iterator which generates augmentations, i.e., elements to add to the set. """ deallocate_sgd(sgd) return NULL
cdef void deallocate_sgd(void *data): r""" Deallocates the data part of the augmentation iterator. """
cdef void *subset_generator_next(void *data, int *degree, bint *mem_err): r""" Returns the next element to consider adding to the set. """
cdef int generate_child_subsets(void *S, aut_gp_and_can_lab *group, iterator *child_iterator): r""" Sets up an iterator of augmentations, i.e., elements to add to the given set. """
cdef void *apply_subset_aug(void *parent, void *aug, void *child, int *degree, bint *mem_err): r""" Adds the element represented by ``aug`` to ``parent``, storing the result to ``child``. """
cdef void free_subset_aug(void *aug): return
cdef void *canonical_set_parent(void *child, void *parent, int *permutation, int *degree, bint *mem_err): r""" Determines the canonical parent of the set ``child`` by applying ``permutation``, deleting the largest element in lexicographic order, and storing the result to ``parent``. """ cdef bitset_t can_par cdef subset *par par = <subset *> allocate_subset(n) if par is NULL: mem_err[0] = 1 else: return NULL
cdef iterator *allocate_subset_gen(int degree, int max_size): r""" Allocates the generator of subsets. """ sig_free(subset_gen) subset_gen = NULL
cdef int allocate_subset_gen_2(int degree, int max_size, iterator *it): r""" Given an already allocated iterator, allocates the generator of subsets. """ return 1 cdef int i, j for j from 0 <= j <= i: deallocate_sgd(cgd.iterator_stack[i].data) free_subset(cgd.object_stack[i]) free_subset(cgd.parent_stack[i]) deallocate_cgd(cgd) return 1
cdef void free_subset_gen(iterator *subset_gen): r""" Frees the iterator of subsets. """
cdef iterator *setup_set_gen(iterator *subset_gen, int degree, int max_size): r""" Initiates the iterator of subsets. """ cdef subset *empty_set &all_set_children_are_equivalent, &refine_set, &compare_sets, &generate_child_subsets, &apply_subset_aug, &free_subset, &deallocate_sgd, &free_subset_aug, &canonical_set_parent, max_size+1, 0, subset_gen)
r""" Given generators of a permutation group, list subsets up to permutations in the group.
INPUT:
- ``generators`` - (list of lists) list of generators in list form - ``max_size`` - (int) maximum size of subsets to be generated - ``indicate_mem_err`` - (bool) whether to raise an error if we run out of memory, or simply append a MemoryError instance to the end of the output
EXAMPLES::
sage: from sage.groups.perm_gps.partn_ref.refinement_sets import sets_modulo_perm_group sage: sets_modulo_perm_group([], 0) [[]] sage: sets_modulo_perm_group([], 1) [[0], []] sage: sets_modulo_perm_group([], 2) [[0, 1], [0], []] sage: sets_modulo_perm_group([], 3) [[0, 1, 2], [0, 1], [0], []] sage: sets_modulo_perm_group([], 4) [[0, 1, 2, 3], [0, 1, 2], [0, 1], [0], []] sage: len(sets_modulo_perm_group([], 99)) 100
::
sage: sets_modulo_perm_group([[1,2,0]], 4) [[0, 1, 2], [0, 1], [0], []] sage: sets_modulo_perm_group([[1,2,0]], 3) [[0, 1, 2], [0, 1], [0], []] sage: sets_modulo_perm_group([[1,2,0]], 2) [[0, 1], [0], []] sage: sets_modulo_perm_group([[1,2,0]], 1) [[0], []] sage: sets_modulo_perm_group([[1,2,0]], 0) [[]] sage: sets_modulo_perm_group([[0,1,2]], 3) [[0, 1, 2], [0, 1], [0, 2], [0], [1, 2], [1], [2], []] sage: sets_modulo_perm_group([[1,0,2]], 3) [[0, 1, 2], [0, 1], [0, 2], [0], [2], []] sage: sets_modulo_perm_group([[1,0,2],[1,2,0]], 3) [[0, 1, 2], [0, 1], [1], []]
::
sage: sets_modulo_perm_group([[1,2,3,0]], 4) [[0, 1, 2, 3], [0, 1, 2], [0, 1], [0, 2], [0], []] sage: sets_modulo_perm_group([[1,2,3,0]], 5) [[0, 1, 2, 3], [0, 1, 2], [0, 1], [0, 2], [0], []] sage: sets_modulo_perm_group([[1,2,3,0]], 3) [[0, 1, 2], [0, 1], [0, 2], [0], []] sage: sets_modulo_perm_group([[1,2,3,0]], 2) [[0, 1], [0, 2], [0], []] sage: sets_modulo_perm_group([[1,2,3,0]], 1) [[0], []] sage: sets_modulo_perm_group([[1,2,3,0]], 0) [[]] sage: sets_modulo_perm_group([[0,1,3,2],[1,0,2,3]], 4) [[0, 1, 2, 3], [0, 1, 2], [0, 1], [0, 2, 3], [0, 2], [0], [2, 3], [2], []] sage: sets_modulo_perm_group([[1,0,2,3],[1,2,0,3]], 4) [[0, 1, 2, 3], [0, 1, 2], [0, 1, 3], [0, 1], [1, 3], [1], [3], []] sage: sets_modulo_perm_group([[1,2,0,3],[0,2,3,1]], 4) [[0, 1, 2, 3], [0, 1, 2], [0, 1], [1], []] sage: sets_modulo_perm_group([[1,0,2,3],[1,2,3,0]], 4) [[0, 1, 2, 3], [0, 1, 2], [1, 2], [2], []] sage: L = list(powerset(range(4))) sage: L.sort() sage: L == sorted(sets_modulo_perm_group([[0,1,2,3]], 4)) True
::
sage: sets_modulo_perm_group([[1,2,3,4,0]], 5) [[0, 1, 2, 3, 4], [0, 1, 2, 3], [0, 1, 2], [0, 1], [0, 2, 3], [0, 2], [0], []] sage: sets_modulo_perm_group([[1,0,2,3,4],[0,1,3,4,2]], 5) [[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], []] sage: L = list(powerset(range(5))) sage: L.sort() sage: L == sorted(sets_modulo_perm_group([[0,1,2,3,4]], 5)) True sage: sets_modulo_perm_group([[1,0,2,3,4],[1,2,3,4,0]], 5) [[0, 1, 2, 3, 4], [0, 1, 2, 3], [1, 2, 3], [2, 3], [3], []] sage: sets_modulo_perm_group([[1,2,0,3,4],[0,2,3,1,4],[0,1,3,4,2]], 5) [[0, 1, 2, 3, 4], [0, 1, 2, 3], [1, 2, 3], [1, 2], [2], []]
::
sage: X = sets_modulo_perm_group([[1,2,3,4,5,0]], 6) sage: [a for a in X if len(a) == 0] [[]] sage: [a for a in X if len(a) == 1] [[0]] sage: [a for a in X if len(a) == 2] [[0, 1], [0, 2], [0, 3]] sage: [a for a in X if len(a) == 3] [[0, 1, 2], [0, 1, 3], [0, 2, 3], [0, 2, 4]] sage: [a for a in X if len(a) == 4] [[0, 1, 2, 3], [0, 1, 3, 4], [0, 2, 3, 4]] sage: [a for a in X if len(a) == 5] [[0, 1, 2, 3, 4]] sage: [a for a in X if len(a) == 6] [[0, 1, 2, 3, 4, 5]]
::
sage: X = sets_modulo_perm_group([[0,2,1,4,3,5,8,7,6],[8,7,6,3,5,4,2,1,0]], 9) sage: len(X) 74
""" cdef int i cdef iterator *subset_iterator cdef subset *thing
SC_dealloc(group) sig_free(gens) raise MemoryError SC_dealloc(group) sig_free(gens) raise MemoryError
SC_dealloc(group) raise MemoryError SC_dealloc(group) free_subset_gen(subset_gen) mem_err = 1 else: if indicate_mem_err: raise MemoryError else: out_list.append(MemoryError())
|