예제 #1
0
def DihedralGroup(n):
    r"""
    Generates the dihedral group `D_n` as a permutation group.

    The dihedral group `D_n` is the group of symmetries of the regular
    ``n``-gon. The generators taken are the ``n``-cycle ``a = (0 1 2 ... n-1)``
    (a rotation of the ``n``-gon) and ``b = (0 n-1)(1 n-2)...``
    (a reflection of the ``n``-gon) in cycle rotation. It is easy to see that
    these satisfy ``a**n = b**2 = 1`` and ``bab = ~a`` so they indeed generate
    `D_n` (See [1]). After the group is generated, some of its basic properties
    are set.

    Examples
    ========

    >>> from sympy.combinatorics.named_groups import DihedralGroup
    >>> G = DihedralGroup(5)
    >>> a = list(G.generate_dimino())
    >>> [perm.cyclic_form for perm in a]
    [[[4], [3], [2], [1], [0]], [[0, 1, 2, 3, 4]], [[0, 2, 4, 1, 3]],
    [[0, 3, 1, 4, 2]], [[0, 4, 3, 2, 1]], [[2], [1, 3], [0, 4]],
    [[2, 3], [1, 4], [0]], [[3], [2, 4], [0, 1]], [[3, 4], [1], [0, 2]],
    [[4], [1, 2], [0, 3]]]

    See Also
    ========

    SymmetricGroup, CyclicGroup, AlternatingGroup

    References
    ==========

    [1] http://en.wikipedia.org/wiki/Dihedral_group

    """
    # small cases are special
    if n == 1:
        return PermutationGroup([Permutation([1, 0])])
    if n == 2:
        return PermutationGroup([
            Permutation([1, 0, 3, 2]),
            Permutation([2, 3, 0, 1]),
            Permutation([3, 2, 1, 0])
        ])

    a = range(1, n)
    a.append(0)
    gen1 = _new_from_array_form(a)
    a = range(n)
    a.reverse()
    gen2 = _new_from_array_form(a)
    G = PermutationGroup([gen1, gen2])

    G._is_abelian = False
    G._degree = n
    G._is_transitive = True
    G._order = 2 * n
    return G
예제 #2
0
def AlternatingGroup(n):
    """
    Generates the alternating group on ``n`` elements as a permutation group.

    For ``n > 2``, the generators taken are ``(0 1 2), (0 1 2 ... n-1)`` for
    ``n`` odd
    and ``(0 1 2), (1 2 ... n-1)`` for ``n`` even (See [1], p.31, ex.6.9.).
    After the group is generated, some of its basic properties are set.
    The cases ``n = 1, 2`` are handled separately.

    Examples
    ========

    >>> from sympy.combinatorics.named_groups import AlternatingGroup
    >>> G = AlternatingGroup(4)
    >>> a = list(G.generate_dimino())
    >>> len(a)
    12
    >>> [perm.is_even for perm in a]
    [True, True, True, True, True, True, True, True, True, True, True, True]

    See Also
    ========

    SymmetricGroup, CyclicGroup, DihedralGroup

    References
    ==========

    [1] Armstrong, M. "Groups and Symmetry"

    """
    # small cases are special
    if n in (1, 2):
        return PermutationGroup([Permutation([0])])

    a = range(n)
    a[0], a[1], a[2] = a[1], a[2], a[0]
    gen1 = _new_from_array_form(a)
    if n % 2:
        a = range(1, n)
        a.append(0)
        gen2 = _new_from_array_form(a)
    else:
        a = range(2, n)
        a.append(1)
        gen2 = _new_from_array_form([0] + a)
    G = PermutationGroup([gen1, gen2])

    if n < 4:
        G._is_abelian = True
    else:
        G._is_abelian = False
    G._degree = n
    G._is_transitive = True
    G._is_alt = True
    return G
예제 #3
0
def AlternatingGroup(n):
    """
    Generates the alternating group on ``n`` elements as a permutation group.

    For ``n > 2``, the generators taken are ``(0 1 2), (0 1 2 ... n-1)`` for
    ``n`` odd
    and ``(0 1 2), (1 2 ... n-1)`` for ``n`` even (See [1], p.31, ex.6.9.).
    After the group is generated, some of its basic properties are set.
    The cases ``n = 1, 2`` are handled separately.

    Examples
    ========

    >>> from sympy.combinatorics.named_groups import AlternatingGroup
    >>> G = AlternatingGroup(4)
    >>> a = list(G.generate_dimino())
    >>> len(a)
    12
    >>> [perm.is_even for perm in a]
    [True, True, True, True, True, True, True, True, True, True, True, True]

    See Also
    ========

    SymmetricGroup, CyclicGroup, DihedralGroup

    References
    ==========

    [1] Armstrong, M. "Groups and Symmetry"

    """
    # small cases are special
    if n in (1, 2):
        return PermutationGroup([Permutation([0])])

    a = range(n)
    a[0], a[1], a[2] = a[1], a[2], a[0]
    gen1 = _new_from_array_form(a)
    if n % 2:
        a = range(1, n)
        a.append(0)
        gen2 = _new_from_array_form(a)
    else:
        a = range(2, n)
        a.append(1)
        gen2 = _new_from_array_form([0] + a)
    G = PermutationGroup([gen1, gen2])

    if n<4:
        G._is_abelian = True
    else:
        G._is_abelian = False
    G._degree = n
    G._is_transitive = True
    G._is_alt = True
    return G
예제 #4
0
    def generate_dimino(self, af=False):
        """
        yield group elements using Dimino's algorithm

        If af == True it yields the array form of the permutations

        Reference:
        [1] The implementation of various algorithms for Permutation Groups in
        the Computer Algebra System: AXIOM, N.J. Doye, M.Sc. Thesis

        Examples
        ========

        >>> from sympy.combinatorics.permutations import Permutation
        >>> from sympy.combinatorics.perm_groups import PermutationGroup
        >>> a = Permutation([0, 2, 1, 3])
        >>> b = Permutation([0, 2, 3, 1])
        >>> g = PermutationGroup([a, b])
        >>> list(g.generate_dimino(af=True))
        [[0, 1, 2, 3], [0, 2, 1, 3], [0, 2, 3, 1], [0, 1, 3, 2], [0, 3, 2, 1], [0, 3, 1, 2]]
        """

        idn = range(self.degree)
        order = 0
        element_list = [idn]
        set_element_list = set([tuple(idn)])
        if af:
            yield idn
        else:
            yield _new_from_array_form(idn)
        gens = [p.array_form for p in self.generators]

        for i in xrange(len(gens)):
            # D elements of the subgroup G_i generated by gens[:i]
            D = element_list[:]
            N = [idn]
            while N:
                A = N
                N = []
                for a in A:
                    for g in gens[:i + 1]:
                        ag = perm_af_mul(a, g)
                        if tuple(ag) not in set_element_list:
                            # produce G_i*g
                            for d in D:
                                order += 1
                                ap = perm_af_mul(d, ag)
                                if af:
                                    yield ap
                                else:
                                    p = _new_from_array_form(ap)
                                    yield p
                                element_list.append(ap)
                                set_element_list.add(tuple(ap))
                                N.append(ap)
        self._order = len(element_list)
예제 #5
0
    def generate_dimino(self, af=False):
        """
        yield group elements using Dimino's algorithm

        If af == True it yields the array form of the permutations

        Reference:
        [1] The implementation of various algorithms for Permutation Groups in
        the Computer Algebra System: AXIOM, N.J. Doye, M.Sc. Thesis

        Examples
        ========

        >>> from sympy.combinatorics.permutations import Permutation
        >>> from sympy.combinatorics.perm_groups import PermutationGroup
        >>> a = Permutation([0, 2, 1, 3])
        >>> b = Permutation([0, 2, 3, 1])
        >>> g = PermutationGroup([a, b])
        >>> list(g.generate_dimino(af=True))
        [[0, 1, 2, 3], [0, 2, 1, 3], [0, 2, 3, 1], [0, 1, 3, 2], [0, 3, 2, 1], [0, 3, 1, 2]]
        """

        idn = range(self.degree)
        order = 0
        element_list = [idn]
        set_element_list = set([tuple(idn)])
        if af:
            yield idn
        else:
            yield _new_from_array_form(idn)
        gens = [p.array_form for p in self.generators]

        for i in xrange(len(gens)):
            # D elements of the subgroup G_i generated by gens[:i]
            D = element_list[:]
            N = [idn]
            while N:
                A = N
                N = []
                for a in A:
                    for g in gens[:i+1]:
                        ag = perm_af_mul(a, g)
                        if tuple(ag) not in set_element_list:
                            # produce G_i*g
                            for d in D:
                                order += 1
                                ap = perm_af_mul(d, ag)
                                if af:
                                    yield ap
                                else:
                                    p = _new_from_array_form(ap)
                                    yield p
                                element_list.append(ap)
                                set_element_list.add(tuple(ap))
                                N.append(ap)
        self._order = len(element_list)
예제 #6
0
def SymmetricGroup(n):
    """
    Generates the symmetric group on ``n`` elements as a permutation group.

    The generators taken are the ``n``-cycle
    ``(0 1 2 ... n-1)`` and the transposition ``(0 1)`` (in cycle notation).
    (See [1]). After the group is generated, some of its basic properties
    are set.

    Examples
    ========

    >>> from sympy.combinatorics.named_groups import SymmetricGroup
    >>> G = SymmetricGroup(4)
    >>> G.order()
    24
    >>> list(G.generate_schreier_sims(af=True))
    [[0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 1, 3], [0, 2, 3, 1], [0, 3, 1, 2],
    [0, 3, 2, 1], [1, 2, 3, 0], [1, 2, 0, 3], [1, 3, 2, 0],
    [1, 3, 0, 2], [1, 0, 2, 3], [1, 0, 3, 2], [2, 3, 0, 1], [2, 3, 1, 0],
    [2, 0, 3, 1], [2, 0, 1, 3], [2, 1, 3, 0], [2, 1, 0, 3], [3, 0, 1, 2],
    [3, 0, 2, 1], [3, 1, 0, 2], [3, 1, 2, 0], [3, 2, 0, 1], [3, 2, 1, 0]]

    See Also
    ========

    CyclicGroup, DihedralGroup, AlternatingGroup

    References
    ==========

    [1] http://en.wikipedia.org/wiki/Symmetric_group#Generators_and_relations

    """
    if n == 1:
        G = PermutationGroup([Permutation([0])])
    elif n == 2:
        G = PermutationGroup([Permutation([1, 0])])
    else:
        a = range(1,n)
        a.append(0)
        gen1 = _new_from_array_form(a)
        a = range(n)
        a[0], a[1] = a[1], a[0]
        gen2 = _new_from_array_form(a)
        G = PermutationGroup([gen1, gen2])

    if n<3:
        G._is_abelian = True
    else:
        G._is_abelian = False
    G._degree = n
    G._is_transitive = True
    G._is_sym = True
    return G
예제 #7
0
def DihedralGroup(n):
    r"""
    Generates the dihedral group `D_n` as a permutation group.

    The dihedral group `D_n` is the group of symmetries of the regular
    ``n``-gon. The generators taken are the ``n``-cycle ``a = (0 1 2 ... n-1)``
    (a rotation of the ``n``-gon) and ``b = (0 n-1)(1 n-2)...``
    (a reflection of the ``n``-gon) in cycle rotation. It is easy to see that
    these satisfy ``a**n = b**2 = 1`` and ``bab = ~a`` so they indeed generate
    `D_n` (See [1]). After the group is generated, some of its basic properties
    are set.

    Examples
    ========

    >>> from sympy.combinatorics.named_groups import DihedralGroup
    >>> G = DihedralGroup(5)
    >>> a = list(G.generate_dimino())
    >>> [perm.cyclic_form for perm in a]
    [[[4], [3], [2], [1], [0]], [[0, 1, 2, 3, 4]], [[0, 2, 4, 1, 3]],
    [[0, 3, 1, 4, 2]], [[0, 4, 3, 2, 1]], [[2], [1, 3], [0, 4]],
    [[2, 3], [1, 4], [0]], [[3], [2, 4], [0, 1]], [[3, 4], [1], [0, 2]],
    [[4], [1, 2], [0, 3]]]

    See Also
    ========

    SymmetricGroup, CyclicGroup, AlternatingGroup

    References
    ==========

    [1] http://en.wikipedia.org/wiki/Dihedral_group

    """
    # small cases are special
    if n == 1:
        return PermutationGroup([Permutation([1, 0])])
    if n == 2:
        return PermutationGroup([Permutation([1, 0, 3, 2]),
               Permutation([2, 3, 0, 1]), Permutation([3, 2, 1, 0])])

    a = range(1, n)
    a.append(0)
    gen1 = _new_from_array_form(a)
    a = range(n)
    a.reverse()
    gen2 = _new_from_array_form(a)
    G = PermutationGroup([gen1, gen2])

    G._is_abelian = False
    G._degree = n
    G._is_transitive = True
    G._order = 2*n
    return G
예제 #8
0
def SymmetricGroup(n):
    """
    Generates the symmetric group on ``n`` elements as a permutation group.

    The generators taken are the ``n``-cycle
    ``(0 1 2 ... n-1)`` and the transposition ``(0 1)`` (in cycle notation).
    (See [1]). After the group is generated, some of its basic properties
    are set.

    Examples
    ========

    >>> from sympy.combinatorics.named_groups import SymmetricGroup
    >>> G = SymmetricGroup(4)
    >>> G.order()
    24
    >>> list(G.generate_schreier_sims(af=True))
    [[0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 1, 3], [0, 2, 3, 1], [0, 3, 1, 2],
    [0, 3, 2, 1], [1, 2, 3, 0], [1, 2, 0, 3], [1, 3, 2, 0],
    [1, 3, 0, 2], [1, 0, 2, 3], [1, 0, 3, 2], [2, 3, 0, 1], [2, 3, 1, 0],
    [2, 0, 3, 1], [2, 0, 1, 3], [2, 1, 3, 0], [2, 1, 0, 3], [3, 0, 1, 2],
    [3, 0, 2, 1], [3, 1, 0, 2], [3, 1, 2, 0], [3, 2, 0, 1], [3, 2, 1, 0]]

    See Also
    ========

    CyclicGroup, DihedralGroup, AlternatingGroup

    References
    ==========

    [1] http://en.wikipedia.org/wiki/Symmetric_group#Generators_and_relations

    """
    if n == 1:
        G = PermutationGroup([Permutation([0])])
    elif n == 2:
        G = PermutationGroup([Permutation([1, 0])])
    else:
        a = range(1, n)
        a.append(0)
        gen1 = _new_from_array_form(a)
        a = range(n)
        a[0], a[1] = a[1], a[0]
        gen2 = _new_from_array_form(a)
        G = PermutationGroup([gen1, gen2])

    if n < 3:
        G._is_abelian = True
    else:
        G._is_abelian = False
    G._degree = n
    G._is_transitive = True
    G._is_sym = True
    return G
예제 #9
0
    def coset_unrank(self, rank, af=False):
        """
        unrank using Schreier-Sims representation

        coset_unrank is the inverse operation of coset_rank
        if 0 <= rank < order; otherwise it returns None.
        """
        u = self.coset_repr()
        if rank < 0 or rank >= self.order():
            return None
        un = self._coset_repr_n
        base = self._base
        m = len(u)
        nb = len(base)
        assert nb == len(un)
        v = [0] * m
        for i in range(nb - 1, -1, -1):
            j = base[i]
            rank, c = divmod(rank, un[i])
            v[j] = c
        a = [u[i][v[i]] for i in range(m)]
        h = perm_af_muln(*a)
        if af:
            return h
        else:
            return _new_from_array_form(h)
예제 #10
0
def CyclicGroup(n):
    """
    Generates the cyclic group of order ``n`` as a permutation group.

    The generator taken is the ``n``-cycle ``(0 1 2 ... n-1)``
    (in cycle notation). After the group is generated, some of its basic
    properties are set.

    Examples
    ========

    >>> from sympy.combinatorics.named_groups import CyclicGroup
    >>> G = CyclicGroup(6)
    >>> G.order()
    6
    >>> list(G.generate_schreier_sims(af=True))
    [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 0], [2, 3, 4, 5, 0, 1],
    [3, 4, 5, 0, 1, 2], [4, 5, 0, 1, 2, 3], [5, 0, 1, 2, 3, 4]]

    See Also
    ========

    SymmetricGroup, DihedralGroup, AlternatingGroup

    """
    a = range(1, n)
    a.append(0)
    gen = _new_from_array_form(a)
    G = PermutationGroup([gen])

    G._is_abelian = True
    G._degree = n
    G._is_transitive = True
    G._order = n
    return G
예제 #11
0
    def coset_unrank(self, rank, af=False):
        """
        unrank using Schreier-Sims representation

        coset_unrank is the inverse operation of coset_rank
        if 0 <= rank < order; otherwise it returns None.
        """
        u = self.coset_repr()
        if rank < 0 or rank >= self.order():
            return None
        un = self._coset_repr_n
        base = self._base
        m = len(u)
        nb = len(base)
        assert nb == len(un)
        v = [0]*m
        for i in range(nb-1, -1,-1):
            j = base[i]
            rank, c = divmod(rank, un[i])
            v[j] = c
        a = [u[i][v[i]] for i in range(m)]
        h = perm_af_muln(*a)
        if af:
            return h
        else:
            return _new_from_array_form(h)
예제 #12
0
def CyclicGroup(n):
    """
    Generates the cyclic group of order ``n`` as a permutation group.

    The generator taken is the ``n``-cycle ``(0 1 2 ... n-1)``
    (in cycle notation). After the group is generated, some of its basic
    properties are set.

    Examples
    ========

    >>> from sympy.combinatorics.named_groups import CyclicGroup
    >>> G = CyclicGroup(6)
    >>> G.order()
    6
    >>> list(G.generate_schreier_sims(af=True))
    [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 0], [2, 3, 4, 5, 0, 1],
    [3, 4, 5, 0, 1, 2], [4, 5, 0, 1, 2, 3], [5, 0, 1, 2, 3, 4]]

    See Also
    ========

    SymmetricGroup, DihedralGroup, AlternatingGroup

    """
    a = range(1, n)
    a.append(0)
    gen = _new_from_array_form(a)
    G = PermutationGroup([gen])

    G._is_abelian = True
    G._degree = n
    G._is_transitive = True
    G._order = n
    return G
예제 #13
0
    def generate_schreier_sims(self, af=False):
        """
        yield group elements using the Schreier-Sims representation

        If af = True it yields the array form of the permutations

        Examples
        ========

        >>> from sympy.combinatorics.permutations import Permutation
        >>> from sympy.combinatorics.perm_groups import PermutationGroup
        >>> a = Permutation([0, 2, 1, 3])
        >>> b = Permutation([0, 2, 3, 1])
        >>> g = PermutationGroup([a, b])
        >>> list(g.generate_schreier_sims(af=True))
        [[0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 3, 1], [0, 2, 1, 3], [0, 3, 2, 1], [0, 3, 1, 2]]
        """

        def get1(posmax):
            n = len(posmax) - 1
            for i in range(n,-1,-1):
                if posmax[i] != 1:
                    return i + 1
        n = self.degree
        u = self.coset_repr()
        # stg stack of group elements
        stg = [range(n)]
        # posmax[i] = len(u[i])
        posmax = [len(x) for x in u]
        n1 = get1(posmax)
        pos = [0]*n1
        posmax = posmax[:n1]
        h = 0
        while 1:
            # backtrack when finished iterating over coset
            if pos[h] >= posmax[h]:
                if h == 0:
                    raise StopIteration
                pos[h] = 0
                h -= 1
                stg.pop()
                continue
            p = perm_af_mul(stg[-1], u[h][pos[h]])
            pos[h] += 1
            stg.append(p)
            h += 1
            if h == n1:
                if af:
                    yield p
                else:
                    p1 = _new_from_array_form(p)
                    yield p1
                stg.pop()
                h -= 1
예제 #14
0
    def generate_schreier_sims(self, af=False):
        """
        yield group elements using the Schreier-Sims representation

        If af = True it yields the array form of the permutations

        Examples
        ========

        >>> from sympy.combinatorics.permutations import Permutation
        >>> from sympy.combinatorics.perm_groups import PermutationGroup
        >>> a = Permutation([0, 2, 1, 3])
        >>> b = Permutation([0, 2, 3, 1])
        >>> g = PermutationGroup([a, b])
        >>> list(g.generate_schreier_sims(af=True))
        [[0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 3, 1], [0, 2, 1, 3], [0, 3, 2, 1], [0, 3, 1, 2]]
        """
        def get1(posmax):
            n = len(posmax) - 1
            for i in range(n, -1, -1):
                if posmax[i] != 1:
                    return i + 1

        n = self.degree
        u = self.coset_repr()
        # stg stack of group elements
        stg = [range(n)]
        # posmax[i] = len(u[i])
        posmax = [len(x) for x in u]
        n1 = get1(posmax)
        pos = [0] * n1
        posmax = posmax[:n1]
        h = 0
        while 1:
            # backtrack when finished iterating over coset
            if pos[h] >= posmax[h]:
                if h == 0:
                    raise StopIteration
                pos[h] = 0
                h -= 1
                stg.pop()
                continue
            p = perm_af_mul(stg[-1], u[h][pos[h]])
            pos[h] += 1
            stg.append(p)
            h += 1
            if h == n1:
                if af:
                    yield p
                else:
                    p1 = _new_from_array_form(p)
                    yield p1
                stg.pop()
                h -= 1
예제 #15
0
def DirectProduct(*groups):
    """
    Returns the direct product of several groups as a permutation group.

    This is implemented much like the __mul__ procedure for taking the direct
    product of two permutation groups, but the idea of shifting the
    generators is realized in the case of an arbitrary number of groups.
    A call to DirectProduct(G1, G2, ..., Gn) is generally expected to be faster
    than a call to G1*G2*...*Gn (and thus the need for this algorithm).

    Examples
    ========

    >>> from sympy.combinatorics.group_constructs import DirectProduct
    >>> from sympy.combinatorics.named_groups import CyclicGroup
    >>> C = CyclicGroup(4)
    >>> G = DirectProduct(C,C,C)
    >>> G.order()
    64

    See Also
    ========
    __mul__

    """
    degrees = []
    gens_count = []
    total_degree = 0
    total_gens = 0
    for group in groups:
        current_deg = group.degree
        current_num_gens = len(group.generators)
        degrees.append(current_deg)
        total_degree += current_deg
        gens_count.append(current_num_gens)
        total_gens += current_num_gens
    array_gens = []
    for i in range(total_gens):
        array_gens.append(range(total_degree))
    current_gen = 0
    current_deg = 0
    for i in xrange(len(gens_count)):
        for j in xrange(current_gen, current_gen + gens_count[i]):
            gen = ((groups[i].generators)[j - current_gen]).array_form
            array_gens[j][current_deg:current_deg + degrees[i]] =\
            [ x + current_deg for x in gen]
        current_gen += gens_count[i]
        current_deg += degrees[i]
    perm_gens = [_new_from_array_form(array) for array in array_gens]
    return PermutationGroup(perm_gens)
예제 #16
0
    def stabilizer(self, alpha):
        """
        return the stabilizer subgroup leaving alpha fixed.

        Examples
        ========

        >>> from sympy.combinatorics.permutations import Permutation
        >>> from sympy.combinatorics.perm_groups import PermutationGroup
        >>> a = Permutation([0, 2, 1, 3])
        >>> b = Permutation([2, 0, 1, 3])
        >>> g = PermutationGroup([a, b])
        >>> g2 = g.stabilizer(2)
        >>> g2
        PermutationGroup([Permutation([1, 0, 2, 3])])
        """
        if alpha == 0:
            self.schreier_sims()
            gens = self._stabilizers_gens
            gens = [_new_from_array_form(p) for p in gens]
            return PermutationGroup(gens)
        # h[alpha] = 0; h[0] = alpha
        n = self.degree
        h = range(n)
        h[0] = alpha
        h[alpha] = 0
        genv = [p.array_form for p in self.generators]
        # conjugate the group to breng alpha to 0
        gens = [_new_from_array_form(perm_af_muln(h, p, h)) for p in genv]
        G = PermutationGroup(gens)
        G.schreier_sims()
        # stabilizers for 0
        gens1 = G._stabilizers_gens
        # conjugate the group
        gens2 = [_new_from_array_form(perm_af_muln(h, p, h)) for p in gens1]
        return PermutationGroup(gens2)
예제 #17
0
    def stabilizer(self, alpha):
        """
        return the stabilizer subgroup leaving alpha fixed.

        Examples
        ========

        >>> from sympy.combinatorics.permutations import Permutation
        >>> from sympy.combinatorics.perm_groups import PermutationGroup
        >>> a = Permutation([0, 2, 1, 3])
        >>> b = Permutation([2, 0, 1, 3])
        >>> g = PermutationGroup([a, b])
        >>> g2 = g.stabilizer(2)
        >>> g2
        PermutationGroup([Permutation([1, 0, 2, 3])])
        """
        if alpha == 0:
            self.schreier_sims()
            gens = self._stabilizers_gens
            gens = [_new_from_array_form(p) for p in gens]
            return PermutationGroup(gens)
        # h[alpha] = 0; h[0] = alpha
        n = self.degree
        h = range(n)
        h[0] = alpha
        h[alpha] = 0
        genv = [p.array_form for p in self.generators]
        # conjugate the group to breng alpha to 0
        gens = [_new_from_array_form(perm_af_muln(h, p, h)) for p in genv]
        G = PermutationGroup(gens)
        G.schreier_sims()
        # stabilizers for 0
        gens1 = G._stabilizers_gens
        # conjugate the group
        gens2 = [_new_from_array_form(perm_af_muln(h, p, h)) for p in gens1]
        return PermutationGroup(gens2)
예제 #18
0
파일: util.py 프로젝트: StefenYin/sympy
def _remove_gens(base, strong_gens, basic_orbits=None, strong_gens_distr=None):
    """
    Remove redundant generators from a strong generating set.

    Parameters
    ==========

    ``base`` - a base
    ``strong_gens`` - a strong generating set relative to ``base``
    ``basic_orbits`` - basic orbits
    ``strong_gens_distr`` - strong generators distributed by membership in basic
    stabilizers

    Returns
    =======

    A strong generating set with respect to ``base`` which is a subset of
    ``strong_gens``.

    Examples
    ========

    >>> from sympy.combinatorics.named_groups import SymmetricGroup
    >>> from sympy.combinatorics.perm_groups import PermutationGroup
    >>> from sympy.combinatorics.util import _remove_gens
    >>> from sympy.combinatorics.testutil import _verify_bsgs
    >>> S = SymmetricGroup(15)
    >>> base, strong_gens = S.schreier_sims_incremental()
    >>> len(strong_gens)
    26
    >>> new_gens = _remove_gens(base, strong_gens)
    >>> len(new_gens)
    14
    >>> _verify_bsgs(S, base, new_gens)
    True

    Notes
    =====

    This procedure is outlined in [1],p.95.

    References
    ==========

    [1] Holt, D., Eick, B., O'Brien, E.
    "Handbook of computational group theory"

    """
    from sympy.combinatorics.perm_groups import PermutationGroup
    base_len = len(base)
    degree = strong_gens[0].size
    identity = _new_from_array_form(range(degree))
    if strong_gens_distr is None:
        strong_gens_distr = _distribute_gens_by_base(base, strong_gens)
    temp = strong_gens_distr[:]
    if basic_orbits is None:
        basic_orbits = []
        for i in range(base_len):
            stab = PermutationGroup(strong_gens_distr[i])
            basic_orbit = stab.orbit(base[i])
            basic_orbits.append(basic_orbit)
    strong_gens_distr.append([])
    res = strong_gens[:]
    for i in range(base_len - 1, -1, -1):
        gens_copy = strong_gens_distr[i][:]
        for gen in strong_gens_distr[i]:
            if gen not in strong_gens_distr[i + 1]:
                temp_gens = gens_copy[:]
                temp_gens.remove(gen)
                if temp_gens == []:
                    continue
                temp_group = PermutationGroup(temp_gens)
                temp_orbit = temp_group.orbit(base[i])
                if temp_orbit == basic_orbits[i]:
                    gens_copy.remove(gen)
                    res.remove(gen)
    return res
예제 #19
0
파일: util.py 프로젝트: StefenYin/sympy
def _distribute_gens_by_base(base, gens):
    """
    Distribute the group elements ``gens`` by membership in basic stabilizers.

    Notice that for a base `(b_1, b_2, ..., b_k)`, the basic stabilizers
    are defined as `G^{(i)} = G_{b_1, ..., b_{i-1}}` for
    `i \in\{1, 2, ..., k\}`.

    Parameters
    ==========

    ``base`` - a sequence of points in `\{0, 1, ..., n-1\}`
    ``gens`` - a list of elements of a permutation group of degree `n`.

    Returns
    =======

    List of length `k`, where `k` is
    the length of ``base``. The `i`-th entry contains those elements in
    ``gens`` which fix the first `i` elements of ``base`` (so that the
    `0`-th entry is equal to ``gens`` itself). If no element fixes the first
    `i` elements of ``base``, the `i`-th element is set to a list containing
    the identity element.

    Examples
    ========

    >>> from sympy.combinatorics.named_groups import DihedralGroup
    >>> from sympy.combinatorics.util import _distribute_gens_by_base
    >>> D = DihedralGroup(3)
    >>> D.schreier_sims()
    >>> D.strong_gens
    [Permutation([1, 2, 0]), Permutation([2, 1, 0]), Permutation([0, 2, 1])]
    >>> D.base
    [0, 1]
    >>> _distribute_gens_by_base(D.base, D.strong_gens)
    [[Permutation([1, 2, 0]), Permutation([2, 1, 0]), Permutation([0, 2, 1])],\
    [Permutation([0, 2, 1])]]

    See Also
    ========

    _strong_gens_from_distr, _orbits_transversals_from_bsgs,
    _handle_precomputed_bsgs

    """
    base_len = len(base)
    stabs = []
    degree = gens[0].size
    for i in xrange(base_len):
        stabs.append([])
    num_gens = len(gens)
    max_stab_index = 0
    for i in xrange(num_gens):
        j = 0
        while j < base_len - 1 and gens[i](base[j]) == base[j]:
            j += 1
        if j > max_stab_index:
            max_stab_index = j
        for k in xrange(j + 1):
            stabs[k].append(gens[i])
    for i in range(max_stab_index + 1, base_len):
        stabs[i].append(_new_from_array_form(range(degree)))
    return stabs
예제 #20
0
파일: util.py 프로젝트: vperic/sympy
def _remove_gens(base, strong_gens, basic_orbits=None, strong_gens_distr=None):
    """
    Remove redundant generators from a strong generating set.

    Parameters
    ==========

    ``base`` - a base
    ``strong_gens`` - a strong generating set relative to ``base``
    ``basic_orbits`` - basic orbits
    ``strong_gens_distr`` - strong generators distributed by membership in basic
    stabilizers

    Returns
    =======

    A strong generating set with respect to ``base`` which is a subset of
    ``strong_gens``.

    Examples
    ========

    >>> from sympy.combinatorics.named_groups import SymmetricGroup
    >>> from sympy.combinatorics.perm_groups import PermutationGroup
    >>> from sympy.combinatorics.util import _remove_gens, _verify_bsgs
    >>> S = SymmetricGroup(15)
    >>> base, strong_gens = S.schreier_sims_incremental()
    >>> len(strong_gens)
    26
    >>> new_gens = _remove_gens(base, strong_gens)
    >>> len(new_gens)
    14
    >>> _verify_bsgs(S, base, new_gens)
    True

    Notes
    =====

    This procedure is outlined in [1],p.95.

    References
    ==========

    [1] Holt, D., Eick, B., O'Brien, E.
    "Handbook of computational group theory"

    """
    from sympy.combinatorics.perm_groups import PermutationGroup
    base_len = len(base)
    degree = strong_gens[0].size
    identity = _new_from_array_form(range(degree))
    if strong_gens_distr is None:
        strong_gens_distr = _distribute_gens_by_base(base, strong_gens)
    temp = strong_gens_distr[:]
    if basic_orbits is None:
        basic_orbits = []
        for i in range(base_len):
            stab = PermutationGroup(strong_gens_distr[i])
            basic_orbit = stab.orbit(base[i])
            basic_orbits.append(basic_orbit)
    strong_gens_distr.append([])
    res = strong_gens[:]
    for i in range(base_len - 1, -1, -1):
        gens_copy = strong_gens_distr[i][:]
        for gen in strong_gens_distr[i]:
            if gen not in strong_gens_distr[i + 1]:
                temp_gens = gens_copy[:]
                temp_gens.remove(gen)
                if temp_gens == []:
                    continue
                temp_group = PermutationGroup(temp_gens)
                temp_orbit = temp_group.orbit(base[i])
                if temp_orbit == basic_orbits[i]:
                    gens_copy.remove(gen)
                    res.remove(gen)
    return res
예제 #21
0
파일: util.py 프로젝트: vperic/sympy
def _distribute_gens_by_base(base, gens):
    """
    Distribute the group elements ``gens`` by membership in basic stabilizers.

    Notice that for a base `(b_1, b_2, ..., b_k)`, the basic stabilizers
    are defined as `G^{(i)} = G_{b_1, ..., b_{i-1}}` for
    `i \in\{1, 2, ..., k\}`.

    Parameters
    ==========

    ``base`` - a sequence of points in `\{0, 1, ..., n-1\}`
    ``gens`` - a list of elements of a permutation group of degree `n`.

    Returns
    =======

    List of length `k`, where `k` is
    the length of ``base``. The `i`-th entry contains those elements in
    ``gens`` which fix the first `i` elements of ``base`` (so that the
    `0`-th entry is equal to ``gens`` itself). If no element fixes the first
    `i` elements of ``base``, the `i`-th element is set to a list containing
    the identity element.

    Examples
    ========

    >>> from sympy.combinatorics.named_groups import DihedralGroup
    >>> from sympy.combinatorics.util import _distribute_gens_by_base
    >>> D = DihedralGroup(3)
    >>> D.schreier_sims()
    >>> D.strong_gens
    [Permutation([1, 2, 0]), Permutation([2, 1, 0]), Permutation([0, 2, 1])]
    >>> D.base
    [0, 1]
    >>> _distribute_gens_by_base(D.base, D.strong_gens)
    [[Permutation([1, 2, 0]), Permutation([2, 1, 0]), Permutation([0, 2, 1])],\
    [Permutation([0, 2, 1])]]

    See Also
    ========

    _strong_gens_from_distr, _orbits_transversals_from_bsgs,
    _handle_precomputed_bsgs

    """
    base_len = len(base)
    stabs = []
    degree = gens[0].size
    for i in xrange(base_len):
        stabs.append([])
    num_gens = len(gens)
    max_stab_index = 0
    for i in xrange(num_gens):
        j = 0
        while j < base_len - 1 and gens[i](base[j]) == base[j]:
            j += 1
        if j > max_stab_index:
            max_stab_index = j
        for k in xrange(j + 1):
            stabs[k].append(gens[i])
    for i in range(max_stab_index + 1, base_len):
        stabs[i].append(_new_from_array_form(range(degree)))
    return stabs